1 /******************************************************************************
2 *
3 * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
4 * Analog Devices, Inc.),
5 * Copyright (C) 2023-2024 Analog Devices, Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 ******************************************************************************/
20
21 #include <stdbool.h>
22 #include <stdio.h>
23 #include <stddef.h>
24 #include <stdint.h>
25 #include "mxc_device.h"
26 #include "mxc_assert.h"
27 #include "mxc_lock.h"
28 #include "mxc_sys.h"
29 #include "mxc_delay.h"
30 #include "dma.h"
31 #include "i2s_reva.h"
32 #include "i2s.h"
33
34 /* ***** Definitions ***** */
35 #define DATALENGTH_EIGHT (8)
36 #define DATALENGTH_SIXTEEN (16)
37 #define DATALENGTH_TWENTY (20)
38 #define DATALENGTH_TWENTYFOUR (24)
39 #define DATALENGTH_THIRTYTWO (32)
40
41 // #define USE_LEGACY_I2S_DMA_CFG
42
43 typedef struct {
44 int rxCnt;
45 int txCnt;
46 bool async;
47 } mxc_i2s_reva_txn_t;
48
49 /* ****** Globals ****** */
50 static mxc_i2s_req_t *request;
51 static void (*dma_cb)(int, int) = NULL;
52 static void (*async_cb)(int) = NULL;
53
54 static mxc_i2s_req_t txn_req;
55 static mxc_i2s_reva_txn_t txn_state;
56 static uint32_t txn_lock = 0;
57
configure_data_sizes(mxc_i2s_reva_regs_t * i2s,uint8_t bits_word,uint8_t smp_sz,uint8_t wsize)58 static void configure_data_sizes(mxc_i2s_reva_regs_t *i2s, uint8_t bits_word, uint8_t smp_sz,
59 uint8_t wsize)
60 {
61 if (bits_word > 0) {
62 MXC_SETFIELD(i2s->ctrl1ch0, MXC_F_I2S_REVA_CTRL1CH0_BITS_WORD,
63 (bits_word - 1) << MXC_F_I2S_REVA_CTRL1CH0_BITS_WORD_POS); // Subtract 1
64 } else {
65 MXC_SETFIELD(i2s->ctrl1ch0, MXC_F_I2S_REVA_CTRL1CH0_BITS_WORD,
66 0); // Clear to 0
67 }
68
69 //Set sample length if defined:
70 //The SMP_SIZE is equal to bitsWord when sampleSize == 0 or sampleSize > bitsWord
71 if (smp_sz > 0) {
72 MXC_SETFIELD(i2s->ctrl1ch0, MXC_F_I2S_REVA_CTRL1CH0_SMP_SIZE,
73 (smp_sz - 1) << MXC_F_I2S_REVA_CTRL1CH0_SMP_SIZE_POS); // Subtract 1
74 } else {
75 MXC_SETFIELD(i2s->ctrl1ch0, MXC_F_I2S_REVA_CTRL1CH0_SMP_SIZE,
76 0); // Clear to 0
77 }
78
79 //Set datasize to load in FIFO
80 MXC_SETFIELD(i2s->ctrl0ch0, MXC_F_I2S_REVA_CTRL0CH0_WSIZE,
81 wsize << MXC_F_I2S_REVA_CTRL0CH0_WSIZE_POS);
82 }
83
84 /* ****** Functions ****** */
MXC_I2S_RevA_Init(mxc_i2s_reva_regs_t * i2s,mxc_i2s_req_t * req)85 int MXC_I2S_RevA_Init(mxc_i2s_reva_regs_t *i2s, mxc_i2s_req_t *req)
86 {
87 if (((req->txData == NULL) || (req->rawData == NULL)) && (req->rxData == NULL)) {
88 return E_NULL_PTR;
89 }
90
91 if (req->length == 0) {
92 return E_BAD_PARAM;
93 }
94
95 request = req;
96
97 if (req->stereoMode) {
98 i2s->ctrl0ch0 |= (req->stereoMode << MXC_F_I2S_REVA_CTRL0CH0_STEREO_POS);
99 }
100
101 //Set RX Threshold 2 (default)
102 i2s->ctrl0ch0 |= (2 << MXC_F_I2S_REVA_CTRL0CH0_RX_THD_VAL_POS);
103
104 //Set justify
105 MXC_SETFIELD(i2s->ctrl0ch0, MXC_F_I2S_REVA_CTRL0CH0_ALIGN,
106 (req->justify) << MXC_F_I2S_REVA_CTRL0CH0_ALIGN_POS);
107
108 if (MXC_I2S_ConfigData((mxc_i2s_req_t *)req) != E_NO_ERROR) {
109 return E_BAD_PARAM;
110 }
111
112 MXC_I2S_SetFrequency(req->channelMode, req->clkdiv);
113
114 return E_NO_ERROR;
115 }
116
MXC_I2S_RevA_Shutdown(mxc_i2s_reva_regs_t * i2s)117 int MXC_I2S_RevA_Shutdown(mxc_i2s_reva_regs_t *i2s)
118 {
119 MXC_I2S_DisableInt(0xFF);
120
121 //Disable I2S TX and RX channel
122 MXC_I2S_TXDisable();
123 MXC_I2S_RXDisable();
124
125 MXC_I2S_Flush();
126
127 //Clear all the registers. Not cleared on reset
128 i2s->ctrl0ch0 = 0x00;
129 i2s->dmach0 = 0x00;
130 i2s->ctrl1ch0 = 0x00;
131
132 i2s->ctrl0ch0 |= MXC_F_I2S_REVA_CTRL0CH0_RST; //Reset channel
133
134 return E_NO_ERROR;
135 }
136
MXC_I2S_RevA_ConfigData(mxc_i2s_reva_regs_t * i2s,mxc_i2s_req_t * req)137 int MXC_I2S_RevA_ConfigData(mxc_i2s_reva_regs_t *i2s, mxc_i2s_req_t *req)
138 {
139 uint32_t dataMask;
140
141 //Data pointers
142 uint8_t *txdata_8 = (uint8_t *)req->txData;
143 uint16_t *txdata_16 = (uint16_t *)req->txData;
144 uint32_t *txdata_32 = (uint32_t *)req->txData;
145 uint8_t *rawdata_8 = (uint8_t *)req->rawData;
146 uint16_t *rawdata_16 = (uint16_t *)req->rawData;
147 uint32_t *rawdata_32 = (uint32_t *)req->rawData;
148
149 if ((req->txData == NULL) && (req->rxData == NULL)) {
150 return E_NULL_PTR;
151 }
152
153 if (req->length == 0) {
154 return E_BAD_PARAM;
155 }
156
157 // Clear configuration bits
158 i2s->ctrl0ch0 &= ~MXC_F_I2S_REVA_CTRL0CH0_WSIZE;
159 i2s->ctrl1ch0 &= ~MXC_F_I2S_REVA_CTRL1CH0_BITS_WORD;
160 i2s->ctrl1ch0 &= ~MXC_F_I2S_REVA_CTRL1CH0_SMP_SIZE;
161
162 configure_data_sizes(i2s, req->bitsWord, req->sampleSize, req->wordSize);
163
164 MXC_SETFIELD(i2s->ctrl1ch0, MXC_F_I2S_REVA_CTRL1CH0_ADJUST,
165 (req->adjust) << MXC_F_I2S_REVA_CTRL1CH0_ADJUST_POS);
166
167 if (req->bitsWord <= DATALENGTH_EIGHT) {
168 dataMask = 0x000000ff;
169
170 if ((req->rawData != NULL) && (req->txData != NULL)) {
171 for (uint32_t i = 0; i < req->length; i++) {
172 *txdata_8++ = *rawdata_8++ & dataMask;
173 }
174 }
175 } else if (req->bitsWord <= DATALENGTH_SIXTEEN) {
176 dataMask = 0x0000ffff;
177
178 if ((req->rawData != NULL) && (req->txData != NULL)) {
179 for (uint32_t i = 0; i < req->length; i++) {
180 *txdata_16++ = *rawdata_16++ & dataMask;
181 }
182 }
183 } else if (req->bitsWord <= DATALENGTH_TWENTY) {
184 dataMask = 0x00fffff;
185
186 if ((req->rawData != NULL) && (req->txData != NULL)) {
187 for (uint32_t i = 0; i < req->length; i++) {
188 *txdata_32++ = (*rawdata_32++ & dataMask) << 12;
189 }
190 }
191 } else if (req->bitsWord <= DATALENGTH_TWENTYFOUR) {
192 dataMask = 0x00ffffff;
193
194 if ((req->rawData != NULL) && (req->txData != NULL)) {
195 for (uint32_t i = 0; i < req->length; i++) {
196 *txdata_32++ = (*rawdata_32++ & dataMask) << 8;
197 }
198 }
199 } else if (req->bitsWord <= DATALENGTH_THIRTYTWO) {
200 dataMask = 0xffffffff;
201
202 if ((req->rawData != NULL) && (req->txData != NULL)) {
203 for (uint32_t i = 0; i < req->length; i++) {
204 *txdata_32++ = *rawdata_32++ & dataMask;
205 }
206 }
207 }
208
209 return E_NO_ERROR;
210 }
211
MXC_I2S_RevA_TXEnable(mxc_i2s_reva_regs_t * i2s)212 void MXC_I2S_RevA_TXEnable(mxc_i2s_reva_regs_t *i2s)
213 {
214 MXC_SETFIELD(i2s->ctrl0ch0, MXC_F_I2S_REVA_CTRL0CH0_TX_EN,
215 1 << MXC_F_I2S_REVA_CTRL0CH0_TX_EN_POS);
216 }
217
MXC_I2S_RevA_TXDisable(mxc_i2s_reva_regs_t * i2s)218 void MXC_I2S_RevA_TXDisable(mxc_i2s_reva_regs_t *i2s)
219 {
220 MXC_SETFIELD(i2s->ctrl0ch0, MXC_F_I2S_REVA_CTRL0CH0_TX_EN,
221 0 << MXC_F_I2S_REVA_CTRL0CH0_TX_EN_POS);
222 }
223
MXC_I2S_RevA_RXEnable(mxc_i2s_reva_regs_t * i2s)224 void MXC_I2S_RevA_RXEnable(mxc_i2s_reva_regs_t *i2s)
225 {
226 MXC_SETFIELD(i2s->ctrl0ch0, MXC_F_I2S_REVA_CTRL0CH0_RX_EN,
227 1 << MXC_F_I2S_REVA_CTRL0CH0_RX_EN_POS);
228 }
229
MXC_I2S_RevA_RXDisable(mxc_i2s_reva_regs_t * i2s)230 void MXC_I2S_RevA_RXDisable(mxc_i2s_reva_regs_t *i2s)
231 {
232 MXC_SETFIELD(i2s->ctrl0ch0, MXC_F_I2S_REVA_CTRL0CH0_RX_EN,
233 0 << MXC_F_I2S_REVA_CTRL0CH0_RX_EN_POS);
234 }
235
MXC_I2S_RevA_SetRXThreshold(mxc_i2s_reva_regs_t * i2s,uint8_t threshold)236 int MXC_I2S_RevA_SetRXThreshold(mxc_i2s_reva_regs_t *i2s, uint8_t threshold)
237 {
238 if ((threshold == 0) || (threshold > 8)) {
239 return E_NOT_SUPPORTED;
240 }
241
242 i2s->ctrl0ch0 |= (threshold << MXC_F_I2S_REVA_CTRL0CH0_RX_THD_VAL_POS);
243
244 return E_NO_ERROR;
245 }
246
MXC_I2S_RevA_SetFrequency(mxc_i2s_reva_regs_t * i2s,mxc_i2s_ch_mode_t mode,uint16_t clkdiv)247 int MXC_I2S_RevA_SetFrequency(mxc_i2s_reva_regs_t *i2s, mxc_i2s_ch_mode_t mode, uint16_t clkdiv)
248 {
249 i2s->ctrl1ch0 &= ~MXC_F_I2S_REVA_CTRL1CH0_EN;
250
251 MXC_SETFIELD(i2s->ctrl0ch0, MXC_F_I2S_REVA_CTRL0CH0_CH_MODE,
252 (mode) << MXC_F_I2S_REVA_CTRL0CH0_CH_MODE_POS);
253
254 i2s->ctrl1ch0 |= ((uint32_t)clkdiv) << MXC_F_I2S_REVA_CTRL1CH0_CLKDIV_POS;
255
256 i2s->ctrl1ch0 |= MXC_F_I2S_REVA_CTRL1CH0_EN;
257
258 return E_NO_ERROR;
259 }
260
MXC_I2S_RevA_SetSampleRate(mxc_i2s_reva_regs_t * i2s,uint32_t smpl_rate,mxc_i2s_wsize_t smpl_sz,uint32_t src_clk)261 int MXC_I2S_RevA_SetSampleRate(mxc_i2s_reva_regs_t *i2s, uint32_t smpl_rate,
262 mxc_i2s_wsize_t smpl_sz, uint32_t src_clk)
263 {
264 int clk_div;
265
266 clk_div = MXC_I2S_RevA_CalculateClockDiv(i2s, smpl_rate, smpl_sz, src_clk);
267 if (clk_div < 0) {
268 return clk_div;
269 }
270
271 i2s->ctrl1ch0 &= ~MXC_F_I2S_REVA_CTRL1CH0_EN;
272 i2s->ctrl1ch0 |= ((uint32_t)clk_div) << MXC_F_I2S_REVA_CTRL1CH0_CLKDIV_POS;
273 i2s->ctrl1ch0 |= MXC_F_I2S_REVA_CTRL1CH0_EN;
274
275 return MXC_I2S_RevA_GetSampleRate(i2s, src_clk);
276 }
277
MXC_I2S_RevA_GetSampleRate(mxc_i2s_reva_regs_t * i2s,uint32_t src_clk)278 int MXC_I2S_RevA_GetSampleRate(mxc_i2s_reva_regs_t *i2s, uint32_t src_clk)
279 {
280 uint16_t word_sz, clk_div;
281 uint32_t bclk;
282
283 word_sz = (i2s->ctrl0ch0 & MXC_F_I2S_REVA_CTRL0CH0_WSIZE) >> MXC_F_I2S_REVA_CTRL0CH0_WSIZE_POS;
284 clk_div = (i2s->ctrl1ch0 & MXC_F_I2S_REVA_CTRL1CH0_CLKDIV) >>
285 MXC_F_I2S_REVA_CTRL1CH0_CLKDIV_POS; // Get clock divider value
286
287 switch (word_sz) { // Get word size
288 case MXC_I2S_WSIZE_BYTE:
289 word_sz = 8;
290 break;
291 case MXC_I2S_WSIZE_HALFWORD:
292 word_sz = 16;
293 break;
294 case MXC_I2S_WSIZE_WORD:
295 default:
296 word_sz = 32;
297 break;
298 }
299
300 bclk = (src_clk / (clk_div + 1)) >>
301 1; // bclk_frequency = src_clk_frequency / (clk_divider + 1) / 2
302 return (bclk / word_sz) >>
303 1; // return sample rate (sample_rate = bclk_frequency / word_size / 2)
304 }
305
MXC_I2S_RevA_CalculateClockDiv(mxc_i2s_reva_regs_t * i2s,uint32_t smpl_rate,mxc_i2s_wsize_t word_sz,uint32_t src_clk)306 int MXC_I2S_RevA_CalculateClockDiv(mxc_i2s_reva_regs_t *i2s, uint32_t smpl_rate,
307 mxc_i2s_wsize_t word_sz, uint32_t src_clk)
308 {
309 uint32_t bclk = 0;
310 uint32_t word_size = 0;
311
312 switch (word_sz) { // Get word size
313 case MXC_I2S_WSIZE_BYTE:
314 word_size = 8;
315 break;
316 case MXC_I2S_WSIZE_HALFWORD:
317 word_size = 16;
318 break;
319 case MXC_I2S_WSIZE_WORD:
320 word_size = 32;
321 break;
322 default:
323 return E_BAD_PARAM;
324 }
325
326 bclk = smpl_rate * word_size * 2; // bclk_frequency = sample_rate * word_size * 2
327
328 if (bclk > src_clk) {
329 return E_INVALID;
330 }
331
332 return (src_clk / (bclk * 2)) - 1; // clk_divider = src_clk_frequency / (bclk_frequency * 2) - 1
333 }
334
MXC_I2S_RevA_Flush(mxc_i2s_reva_regs_t * i2s)335 void MXC_I2S_RevA_Flush(mxc_i2s_reva_regs_t *i2s)
336 {
337 i2s->ctrl0ch0 |= MXC_F_I2S_REVA_CTRL0CH0_FLUSH;
338
339 while (i2s->ctrl0ch0 & MXC_F_I2S_REVA_CTRL0CH0_FLUSH) {}
340 }
341
write_tx_fifo(void * tx,mxc_i2s_wsize_t wordSize,int smpl_cnt)342 static uint32_t write_tx_fifo(void *tx, mxc_i2s_wsize_t wordSize, int smpl_cnt)
343 {
344 uint32_t write_val = 0;
345
346 if (wordSize == MXC_I2S_WSIZE_BYTE) {
347 uint8_t *tx8 = (uint8_t *)tx;
348 for (int i = 0; i < 4; i++) {
349 write_val |= (tx8[smpl_cnt++] << (i * 8));
350 }
351 } else if (wordSize == MXC_I2S_WSIZE_HALFWORD) {
352 uint16_t *tx16 = (uint16_t *)tx;
353 for (int i = 0; i < 2; i++) {
354 write_val |= (tx16[smpl_cnt++] << (i * 16));
355 }
356 } else if (wordSize == MXC_I2S_WSIZE_WORD) {
357 uint32_t *tx32 = (uint32_t *)tx;
358 write_val = tx32[smpl_cnt];
359 }
360
361 return write_val;
362 }
363
MXC_I2S_RevA_FillTXFIFO(mxc_i2s_reva_regs_t * i2s,void * txData,mxc_i2s_wsize_t wordSize,int len,int smpl_cnt)364 int MXC_I2S_RevA_FillTXFIFO(mxc_i2s_reva_regs_t *i2s, void *txData, mxc_i2s_wsize_t wordSize,
365 int len, int smpl_cnt)
366 {
367 int num_smpl = 0x4 >> wordSize; // Number of samples per FIFO write
368 int sent = 0; // Total number of samples transmitted
369 uint32_t fifo_write, fifo_avail; // Value to write to I2S TX FIFO
370
371 if (txData == NULL) { // Check for bad parameters
372 return E_NULL_PTR;
373 } else if (wordSize > MXC_I2S_WSIZE_WORD) {
374 return E_BAD_PARAM;
375 } else if (len == 0) {
376 return E_NO_ERROR;
377 }
378
379 len -= len % num_smpl; // TEST
380 fifo_avail =
381 8 - ((i2s->dmach0 & MXC_F_I2S_REVA_DMACH0_TX_LVL) >> MXC_F_I2S_REVA_DMACH0_TX_LVL_POS);
382 fifo_avail *= num_smpl;
383 while (sent < len && sent < fifo_avail) {
384 fifo_write = write_tx_fifo(txData, wordSize, sent + smpl_cnt);
385 sent += num_smpl;
386
387 i2s->fifoch0 = fifo_write;
388 }
389
390 return sent;
391 }
392
read_rx_fifo(mxc_i2s_reva_regs_t * i2s,void * rxData,mxc_i2s_wsize_t wordSize,int cnt)393 static void read_rx_fifo(mxc_i2s_reva_regs_t *i2s, void *rxData, mxc_i2s_wsize_t wordSize, int cnt)
394 {
395 uint32_t fifo_val = i2s->fifoch0;
396
397 if (wordSize == MXC_I2S_WSIZE_BYTE) {
398 uint8_t *rx8 = (uint8_t *)rxData;
399 for (int i = 0; i < 4; i++) {
400 rx8[cnt++] = fifo_val & 0xFF;
401 fifo_val = fifo_val >> 8;
402 }
403 } else if (wordSize == MXC_I2S_WSIZE_HALFWORD) {
404 uint16_t *rx16 = (uint16_t *)rxData;
405 for (int i = 0; i < 2; i++) {
406 rx16[cnt++] = fifo_val & 0xFFFF;
407 fifo_val = fifo_val >> 16;
408 }
409 } else if (wordSize == MXC_I2S_WSIZE_WORD) {
410 uint32_t *rx32 = (uint32_t *)rxData;
411 rx32[cnt] = fifo_val;
412 }
413 }
414
MXC_I2S_RevA_ReadRXFIFO(mxc_i2s_reva_regs_t * i2s,void * rxData,mxc_i2s_wsize_t wordSize,int len,int smpl_cnt)415 int MXC_I2S_RevA_ReadRXFIFO(mxc_i2s_reva_regs_t *i2s, void *rxData, mxc_i2s_wsize_t wordSize,
416 int len, int smpl_cnt)
417 {
418 int received = 0;
419 int num_smpl = 0x4 >> wordSize;
420 uint32_t fifo_avail;
421
422 if (rxData == NULL) { // Check for bad parameters
423 return E_NULL_PTR;
424 } else if (wordSize > MXC_I2S_WSIZE_WORD) {
425 return E_BAD_PARAM;
426 } else if (len == 0) {
427 return E_NO_ERROR;
428 }
429
430 len -= len % num_smpl;
431 fifo_avail = (i2s->dmach0 & MXC_F_I2S_REVA_DMACH0_RX_LVL) >> MXC_F_I2S_REVA_DMACH0_RX_LVL_POS;
432 while (received < len && fifo_avail) {
433 read_rx_fifo(i2s, rxData, wordSize, received + smpl_cnt);
434 received += num_smpl;
435 fifo_avail = (i2s->dmach0 & MXC_F_I2S_REVA_DMACH0_RX_LVL) >>
436 MXC_F_I2S_REVA_DMACH0_RX_LVL_POS;
437 }
438
439 return received;
440 }
441
MXC_I2S_RevA_EnableInt(mxc_i2s_reva_regs_t * i2s,uint32_t flags)442 void MXC_I2S_RevA_EnableInt(mxc_i2s_reva_regs_t *i2s, uint32_t flags)
443 {
444 i2s->inten |= flags;
445 }
446
MXC_I2S_RevA_DisableInt(mxc_i2s_reva_regs_t * i2s,uint32_t flags)447 void MXC_I2S_RevA_DisableInt(mxc_i2s_reva_regs_t *i2s, uint32_t flags)
448 {
449 i2s->inten &= ~flags;
450 }
451
MXC_I2S_RevA_GetFlags(mxc_i2s_reva_regs_t * i2s)452 int MXC_I2S_RevA_GetFlags(mxc_i2s_reva_regs_t *i2s)
453 {
454 return (i2s->intfl & 0xF);
455 }
456
MXC_I2S_RevA_ClearFlags(mxc_i2s_reva_regs_t * i2s,uint32_t flags)457 void MXC_I2S_RevA_ClearFlags(mxc_i2s_reva_regs_t *i2s, uint32_t flags)
458 {
459 i2s->intfl |= flags;
460 }
461
MXC_I2S_RevA_Transaction(mxc_i2s_reva_regs_t * i2s,mxc_i2s_req_t * i2s_req)462 int MXC_I2S_RevA_Transaction(mxc_i2s_reva_regs_t *i2s, mxc_i2s_req_t *i2s_req)
463 {
464 int err;
465
466 if (i2s_req->rawData != NULL && i2s_req->txData == NULL) {
467 return E_INVALID;
468 } else if (i2s_req->length == 0) {
469 return E_INVALID;
470 } else if (MXC_GetLock(&txn_lock, 1) != E_NO_ERROR) {
471 return E_BUSY;
472 }
473
474 i2s->ctrl1ch0 &= ~MXC_F_I2S_REVA_CTRL1CH0_EN; // Disable I2S while it's being configured
475
476 txn_req = *i2s_req; // Initialize transaction request state variables
477 txn_state.rxCnt = txn_req.length;
478 txn_state.txCnt = txn_req.length;
479 txn_state.async = false;
480
481 MXC_I2S_Flush();
482
483 if (txn_req.rawData != NULL &&
484 txn_req.txData != NULL) { // Set up transmit if transmit parameters valid
485 txn_state.txCnt = 0;
486
487 err = MXC_I2S_ConfigData(&txn_req);
488 if (err) {
489 MXC_FreeLock(&txn_lock);
490 return err;
491 }
492
493 err = MXC_I2S_FillTXFIFO(txn_req.txData, txn_req.wordSize, txn_req.length,
494 txn_state.txCnt); // Initialize TX FIFO
495 if (err < E_NO_ERROR) {
496 MXC_FreeLock(&txn_lock);
497 return err;
498 }
499 txn_state.txCnt = err;
500
501 MXC_I2S_TXEnable(); // Enable I2S transmit (Do this before Fill FIFO?)
502 }
503
504 if (txn_req.rxData != NULL) { // Setup I2S receive if receive parameters valid
505 txn_state.rxCnt = 0;
506
507 MXC_SETFIELD(i2s->ctrl0ch0, MXC_F_I2S_REVA_CTRL0CH0_RX_THD_VAL,
508 (6 << MXC_F_I2S_REVA_CTRL0CH0_RX_THD_VAL_POS)); // Set RX threshold
509
510 MXC_I2S_RXEnable(); // Enable I2S Receive
511 }
512
513 i2s->ctrl1ch0 |= MXC_F_I2S_REVA_CTRL1CH0_EN; // Enable I2S RX/TX
514
515 while (MXC_GetLock(&txn_lock, 1) != E_NO_ERROR) {
516 MXC_I2S_RevA_Handler(i2s);
517 }
518
519 MXC_FreeLock(&txn_lock);
520
521 return E_NO_ERROR;
522 }
523
MXC_I2S_RevA_TransactionAsync(mxc_i2s_reva_regs_t * i2s,mxc_i2s_req_t * i2s_req)524 int MXC_I2S_RevA_TransactionAsync(mxc_i2s_reva_regs_t *i2s, mxc_i2s_req_t *i2s_req)
525 {
526 int err;
527 uint32_t int_en = 0;
528
529 if (i2s_req->rawData != NULL && i2s_req->txData == NULL) {
530 return E_INVALID;
531 } else if (i2s_req->length == 0) {
532 return E_INVALID;
533 } else if (MXC_GetLock(&txn_lock, 1) != E_NO_ERROR) {
534 return E_BUSY;
535 }
536
537 i2s->ctrl1ch0 &= ~MXC_F_I2S_REVA_CTRL1CH0_EN; // Disable I2S while it's being configured
538
539 txn_req = *i2s_req; // Initialize transacion request state variables
540 txn_state.rxCnt = txn_req.length;
541 txn_state.txCnt = txn_req.length;
542 txn_state.async = true;
543
544 MXC_I2S_Flush();
545
546 if (txn_req.rawData != NULL &&
547 txn_req.txData != NULL) { // Set up transmit if transmit parameters valid
548 txn_state.txCnt = 0;
549
550 err = MXC_I2S_ConfigData(&txn_req);
551 if (err) {
552 MXC_FreeLock(&txn_lock);
553 return err;
554 }
555
556 int_en |= MXC_F_I2S_REVA_INTFL_TX_OB_CH0; // Enable TX one entry remaining interrupt
557
558 err = MXC_I2S_FillTXFIFO(txn_req.txData, txn_req.wordSize, txn_req.length,
559 txn_state.txCnt); // Initialize TX FIFO
560 if (err < E_NO_ERROR) {
561 MXC_FreeLock(&txn_lock);
562 return err;
563 }
564 txn_state.txCnt = err;
565
566 MXC_I2S_TXEnable(); // Enable I2S transmit (Do this before Fill FIFO?)
567 }
568
569 if (txn_req.rxData != NULL) { // Setup I2S receive if receive parameters valid
570 txn_state.rxCnt = 0;
571
572 int_en |= MXC_F_I2S_REVA_INTEN_RX_THD_CH0; // Enable RX threshold interrupt
573 MXC_SETFIELD(i2s->ctrl0ch0, MXC_F_I2S_REVA_CTRL0CH0_RX_THD_VAL,
574 (6 << MXC_F_I2S_REVA_CTRL0CH0_RX_THD_VAL_POS)); // Set RX threshold
575
576 MXC_I2S_RXEnable(); // Enable I2S Receive
577 }
578
579 MXC_I2S_DisableInt(0xF); // Configure interrupts
580 MXC_I2S_ClearFlags(0xF);
581 MXC_I2S_EnableInt(int_en);
582
583 i2s->ctrl1ch0 |= MXC_F_I2S_REVA_CTRL1CH0_EN; // Enable I2S RX/TX
584
585 return E_NO_ERROR;
586 }
587
MXC_I2S_RevA_TXDMAConfig(mxc_i2s_reva_regs_t * i2s,void * src_addr,int len)588 int MXC_I2S_RevA_TXDMAConfig(mxc_i2s_reva_regs_t *i2s, void *src_addr, int len)
589 {
590 int channel;
591 mxc_dma_config_t config;
592 mxc_dma_adv_config_t advConfig;
593 mxc_dma_srcdst_t srcdst;
594
595 MXC_DMA_Init();
596
597 i2s->dmach0 |= (2 << MXC_F_I2S_REVA_DMACH0_DMA_TX_THD_VAL_POS); //TX DMA Threshold
598
599 channel = MXC_DMA_AcquireChannel();
600 if (channel < E_NO_ERROR) {
601 return channel;
602 }
603
604 config.reqsel = MXC_DMA_REQUEST_I2STX;
605
606 config.ch = channel;
607
608 switch (request->wordSize) {
609 case MXC_I2S_WSIZE_WORD:
610 config.srcwd = MXC_DMA_WIDTH_WORD;
611 config.dstwd = MXC_DMA_WIDTH_WORD;
612 advConfig.burst_size = 4;
613 break;
614
615 case MXC_I2S_WSIZE_HALFWORD:
616 config.srcwd = MXC_DMA_WIDTH_HALFWORD;
617 config.dstwd = MXC_DMA_WIDTH_WORD;
618 advConfig.burst_size = 2;
619 break;
620
621 case MXC_I2S_WSIZE_BYTE:
622 config.srcwd = MXC_DMA_WIDTH_BYTE;
623 config.dstwd = MXC_DMA_WIDTH_WORD;
624 advConfig.burst_size = 1;
625 break;
626
627 default:
628 config.srcwd = MXC_DMA_WIDTH_BYTE;
629 config.dstwd = MXC_DMA_WIDTH_WORD;
630 advConfig.burst_size = 1;
631 break;
632 }
633
634 #ifndef USE_LEGACY_I2S_DMA_CFG
635 advConfig.burst_size = 4;
636 #endif
637
638 config.srcinc_en = 1;
639 config.dstinc_en = 0;
640
641 advConfig.ch = channel;
642 advConfig.prio = MXC_DMA_PRIO_HIGH; // 0
643 advConfig.reqwait_en = 0;
644 advConfig.tosel = MXC_DMA_TIMEOUT_4_CLK; // 0
645 advConfig.pssel = MXC_DMA_PRESCALE_DISABLE; // 0
646
647 srcdst.ch = channel;
648 srcdst.source = src_addr;
649 srcdst.len = len;
650
651 MXC_DMA_ConfigChannel(config, srcdst);
652 MXC_DMA_AdvConfigChannel(advConfig);
653 MXC_DMA_SetCallback(channel, dma_cb);
654
655 MXC_I2S_TXEnable(); //Enable I2S TX
656 i2s->dmach0 |= MXC_F_I2S_REVA_DMACH0_DMA_TX_EN; //Enable I2S DMA
657
658 MXC_DMA_EnableInt(channel);
659 MXC_DMA_Start(channel);
660 MXC_DMA->ch[channel].ctrl |= MXC_F_DMA_CTRL_CTZ_IE;
661
662 return channel;
663 }
664
MXC_I2S_RevA_RXDMAConfig(mxc_i2s_reva_regs_t * i2s,void * dest_addr,int len)665 int MXC_I2S_RevA_RXDMAConfig(mxc_i2s_reva_regs_t *i2s, void *dest_addr, int len)
666 {
667 int channel;
668 mxc_dma_config_t config;
669 mxc_dma_adv_config_t advConfig;
670 mxc_dma_srcdst_t srcdst;
671
672 MXC_DMA_Init();
673
674 i2s->dmach0 |= (6 << MXC_F_I2S_REVA_DMACH0_DMA_RX_THD_VAL_POS); //RX DMA Threshold
675
676 channel = MXC_DMA_AcquireChannel();
677 if (channel < E_NO_ERROR) {
678 return channel;
679 }
680
681 config.reqsel = MXC_DMA_REQUEST_I2SRX;
682
683 config.ch = channel;
684
685 switch (request->wordSize) {
686 case MXC_I2S_WSIZE_WORD:
687 config.srcwd = MXC_DMA_WIDTH_WORD;
688 config.dstwd = MXC_DMA_WIDTH_WORD;
689 advConfig.burst_size = 4;
690 break;
691
692 case MXC_I2S_WSIZE_HALFWORD:
693 config.srcwd = MXC_DMA_WIDTH_WORD;
694 config.dstwd = MXC_DMA_WIDTH_HALFWORD;
695 advConfig.burst_size = 2;
696 break;
697
698 case MXC_I2S_WSIZE_BYTE:
699 config.srcwd = MXC_DMA_WIDTH_WORD;
700 config.dstwd = MXC_DMA_WIDTH_BYTE;
701 advConfig.burst_size = 1;
702 break;
703
704 default:
705 config.srcwd = MXC_DMA_WIDTH_WORD;
706 config.dstwd = MXC_DMA_WIDTH_BYTE;
707 advConfig.burst_size = 1;
708 break;
709 }
710
711 #ifndef USE_LEGACY_I2S_DMA_CFG
712 advConfig.burst_size = 4;
713 #endif
714
715 config.srcinc_en = 0;
716 config.dstinc_en = 1;
717
718 advConfig.ch = channel;
719 advConfig.prio = MXC_DMA_PRIO_HIGH; // 0
720 advConfig.reqwait_en = 0;
721 advConfig.tosel = MXC_DMA_TIMEOUT_4_CLK; // 0
722 advConfig.pssel = MXC_DMA_PRESCALE_DISABLE; // 0
723
724 srcdst.ch = channel;
725 srcdst.dest = dest_addr;
726 srcdst.len = len;
727
728 MXC_DMA_ConfigChannel(config, srcdst);
729 MXC_DMA_AdvConfigChannel(advConfig);
730 MXC_DMA_SetCallback(channel, dma_cb);
731
732 MXC_I2S_RXEnable(); //Enable I2S RX
733 i2s->dmach0 |= MXC_F_I2S_REVA_DMACH0_DMA_RX_EN; //Enable I2S DMA
734
735 MXC_DMA_EnableInt(channel);
736 MXC_DMA_Start(channel);
737 MXC_DMA->ch[channel].ctrl |= MXC_F_DMA_CTRL_CTZ_IE;
738
739 return channel;
740 }
741
MXC_I2S_RevA_Handler(mxc_i2s_reva_regs_t * i2s)742 void MXC_I2S_RevA_Handler(mxc_i2s_reva_regs_t *i2s)
743 {
744 uint32_t flags = MXC_I2S_GetFlags();
745
746 if (txn_state.txCnt == txn_req.length && txn_state.rxCnt == txn_req.length) {
747 MXC_I2S_DisableInt(MXC_F_I2S_REVA_INTEN_TX_OB_CH0 | MXC_F_I2S_REVA_INTEN_RX_THD_CH0);
748 MXC_I2S_ClearFlags(MXC_F_I2S_REVA_INTFL_TX_OB_CH0 | MXC_F_I2S_REVA_INTFL_RX_THD_CH0);
749
750 while (i2s->dmach0 & MXC_F_I2S_REVA_DMACH0_TX_LVL) {}
751
752 MXC_I2S_TXDisable();
753 MXC_I2S_RXDisable();
754
755 if (async_cb != NULL && txn_state.async) {
756 async_cb(E_NO_ERROR);
757 }
758
759 MXC_FreeLock(&txn_lock);
760 } else if (txn_req.txData != NULL && (flags & MXC_F_I2S_REVA_INTFL_TX_OB_CH0)) {
761 MXC_I2S_ClearFlags(MXC_F_I2S_REVA_INTFL_TX_OB_CH0);
762
763 if (txn_state.txCnt < txn_req.length) {
764 txn_state.txCnt += MXC_I2S_FillTXFIFO(txn_req.txData, txn_req.wordSize,
765 (txn_req.length - txn_state.txCnt),
766 txn_state.txCnt);
767 }
768 } else if (txn_req.rxData != NULL && (flags & MXC_F_I2S_REVA_INTFL_RX_THD_CH0)) {
769 MXC_I2S_ClearFlags(MXC_F_I2S_REVA_INTFL_RX_THD_CH0);
770
771 if (txn_state.rxCnt < txn_req.length) {
772 txn_state.rxCnt += MXC_I2S_ReadRXFIFO(txn_req.rxData, txn_req.wordSize,
773 (txn_req.length - txn_state.rxCnt),
774 txn_state.rxCnt);
775 }
776 }
777 }
778
MXC_I2S_RevA_RegisterDMACallback(void (* callback)(int,int))779 void MXC_I2S_RevA_RegisterDMACallback(void (*callback)(int, int))
780 {
781 dma_cb = callback;
782 }
783
MXC_I2S_RevA_RegisterAsyncCallback(void (* callback)(int))784 void MXC_I2S_RevA_RegisterAsyncCallback(void (*callback)(int))
785 {
786 async_cb = callback;
787 }
788