1 /*
2 * Copyright (c) 2016, Freescale Semiconductor, Inc.
3 * Copyright 2016-2022 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_i2s.h"
10 #include "fsl_flexcomm.h"
11 #include <string.h>
12
13 /*******************************************************************************
14 * Definitions
15 ******************************************************************************/
16
17 /* Component ID definition, used by tools. */
18 #ifndef FSL_COMPONENT_ID
19 #define FSL_COMPONENT_ID "platform.drivers.flexcomm_i2s"
20 #endif
21
22 /* TODO - absent in device header files, should be there */
23 #define I2S_FIFOCFG_TXI2SE0_MASK (0x4U)
24 #define I2S_FIFOCFG_TXI2SE0_SHIFT (2U)
25 #define I2S_FIFOCFG_TXI2SE0(x) (((uint32_t)(((uint32_t)(x)) << I2S_FIFOCFG_TXI2SE0_SHIFT)) & I2S_FIFOCFG_TXI2SE0_MASK)
26 #define I2S_FIFOCFG_PACK48_MASK (0x8U)
27 #define I2S_FIFOCFG_PACK48_SHIFT (3U)
28 #define I2S_FIFOCFG_PACK48(x) (((uint32_t)(((uint32_t)(x)) << I2S_FIFOCFG_PACK48_SHIFT)) & I2S_FIFOCFG_PACK48_MASK)
29 /*! @brief i2s empty tx fifo timeout value */
30 #define I2S_FIFO_DEPTH (8U)
31 #define I2S_TX_ONE_SAMPLE_MAX_TIMEOUT (125U) /* 8K/8bit one sample need 125us*/
32 #define I2S_TX_FIFO_EMPTY_TIMEOUT(count) (count) * I2S_TX_ONE_SAMPLE_MAX_TIMEOUT
33 /*! @brief _i2s_state I2S states. */
34 enum
35 {
36 kI2S_StateIdle = 0x0, /*!< Not performing transfer */
37 kI2S_StateTx, /*!< Performing transmit */
38 kI2S_StateTxWaitToWriteDummyData, /*!< Wait on FIFO in order to write final dummy data there */
39 kI2S_StateTxWaitForEmptyFifo, /*!< Wait for FIFO to be flushed */
40 kI2S_StateRx, /*!< Performing receive */
41 };
42
43 /*******************************************************************************
44 * Prototypes
45 ******************************************************************************/
46
47 static void I2S_Config(I2S_Type *base, const i2s_config_t *config);
48 static void I2S_TxEnable(I2S_Type *base, bool enable);
49 static void I2S_RxEnable(I2S_Type *base, bool enable);
50 static status_t I2S_ValidateBuffer(i2s_handle_t *handle, i2s_transfer_t *transfer);
51
52 /*******************************************************************************
53 * Variables
54 ******************************************************************************/
55
56 /*! @brief Array to map i2c instance number to base address. */
57 static const uint32_t s_i2sBaseAddrs[] = I2S_BASE_ADDRS;
58
59 /*! @brief IRQ name array */
60 static const IRQn_Type s_i2sIRQ[] = I2S_IRQS;
61
62 /*******************************************************************************
63 * Code
64 ******************************************************************************/
65 /*!
66 * @brief Returns an instance number given a base address.
67 *
68 * If an invalid base address is passed, debug builds will assert. Release builds will just return
69 * instance number 0.
70 *
71 * @param base The I2S peripheral base address.
72 * @return I2S instance number starting from 0.
73 */
I2S_GetInstance(I2S_Type * base)74 static uint32_t I2S_GetInstance(I2S_Type *base)
75 {
76 uint32_t i;
77 for (i = 0; i < (uint32_t)ARRAY_SIZE(s_i2sBaseAddrs); i++)
78 {
79 if ((uint32_t)base == s_i2sBaseAddrs[i])
80 {
81 return i;
82 }
83 }
84 assert(false);
85 return 0;
86 }
87
88 /*!
89 * brief Transmitter bit clock rate configurations.
90 *
91 * param base SAI base pointer.
92 * param sourceClockHz, bit clock source frequency.
93 * param sampleRate audio data sample rate.
94 * param bitWidth, audio data bitWidth.
95 * param channelNumbers, audio channel numbers.
96 */
I2S_SetBitClockRate(I2S_Type * base,uint32_t sourceClockHz,uint32_t sampleRate,uint32_t bitWidth,uint32_t channelNumbers)97 void I2S_SetBitClockRate(
98 I2S_Type *base, uint32_t sourceClockHz, uint32_t sampleRate, uint32_t bitWidth, uint32_t channelNumbers)
99 {
100 uint32_t bitClockDivider = sourceClockHz / sampleRate / bitWidth / channelNumbers;
101
102 assert(bitClockDivider >= 1U);
103 base->DIV = I2S_DIV_DIV(bitClockDivider - 1U);
104 }
105
106 /*!
107 * brief Initializes the FLEXCOMM peripheral for I2S transmit functionality.
108 *
109 * Ungates the FLEXCOMM clock and configures the module
110 * for I2S transmission using a configuration structure.
111 * The configuration structure can be custom filled or set with default values by
112 * I2S_TxGetDefaultConfig().
113 *
114 * note This API should be called at the beginning of the application to use
115 * the I2S driver.
116 *
117 * param base I2S base pointer.
118 * param config pointer to I2S configuration structure.
119 */
I2S_TxInit(I2S_Type * base,const i2s_config_t * config)120 void I2S_TxInit(I2S_Type *base, const i2s_config_t *config)
121 {
122 uint32_t cfg = 0U;
123 uint32_t trig = 0U;
124
125 (void)FLEXCOMM_Init(base, FLEXCOMM_PERIPH_I2S_TX);
126 I2S_Config(base, config);
127
128 /* Configure FIFO */
129
130 cfg |= I2S_FIFOCFG_ENABLETX(1U); /* enable TX FIFO */
131 cfg |= I2S_FIFOCFG_EMPTYTX(1U); /* empty TX FIFO */
132 cfg |= I2S_FIFOCFG_TXI2SE0(config->txEmptyZero); /* transmit zero when buffer becomes empty or last item */
133 cfg |= I2S_FIFOCFG_PACK48(config->pack48); /* set pack 48-bit format or not */
134 trig |= I2S_FIFOTRIG_TXLVLENA(1U); /* enable TX FIFO trigger */
135 trig |= I2S_FIFOTRIG_TXLVL(config->watermark); /* set TX FIFO trigger level */
136
137 base->FIFOCFG = cfg;
138 base->FIFOTRIG = trig;
139 }
140
141 /*!
142 * brief Initializes the FLEXCOMM peripheral for I2S receive functionality.
143 *
144 * Ungates the FLEXCOMM clock and configures the module
145 * for I2S receive using a configuration structure.
146 * The configuration structure can be custom filled or set with default values by
147 * I2S_RxGetDefaultConfig().
148 *
149 * note This API should be called at the beginning of the application to use
150 * the I2S driver.
151 *
152 * param base I2S base pointer.
153 * param config pointer to I2S configuration structure.
154 */
I2S_RxInit(I2S_Type * base,const i2s_config_t * config)155 void I2S_RxInit(I2S_Type *base, const i2s_config_t *config)
156 {
157 uint32_t cfg = 0U;
158 uint32_t trig = 0U;
159
160 (void)FLEXCOMM_Init(base, FLEXCOMM_PERIPH_I2S_RX);
161 I2S_Config(base, config);
162
163 /* Configure FIFO */
164
165 cfg |= I2S_FIFOCFG_ENABLERX(1U); /* enable RX FIFO */
166 cfg |= I2S_FIFOCFG_EMPTYRX(1U); /* empty RX FIFO */
167 cfg |= I2S_FIFOCFG_PACK48(config->pack48); /* set pack 48-bit format or not */
168 trig |= I2S_FIFOTRIG_RXLVLENA(1U); /* enable RX FIFO trigger */
169 trig |= I2S_FIFOTRIG_RXLVL(config->watermark); /* set RX FIFO trigger level */
170
171 base->FIFOCFG = cfg;
172 base->FIFOTRIG = trig;
173 }
174
175 /*!
176 * brief Flush the valid data in TX fifo.
177 *
178 * param base I2S base pointer.
179 * return kStatus_Fail empty TX fifo failed, kStatus_Success empty tx fifo success.
180 */
I2S_EmptyTxFifo(I2S_Type * base)181 status_t I2S_EmptyTxFifo(I2S_Type *base)
182 {
183 uint32_t timeout = I2S_TX_FIFO_EMPTY_TIMEOUT(I2S_FIFO_DEPTH);
184
185 while (((base->FIFOSTAT & I2S_FIFOSTAT_TXEMPTY_MASK) == 0U) && (timeout != 0U))
186 {
187 timeout -= I2S_TX_ONE_SAMPLE_MAX_TIMEOUT;
188 SDK_DelayAtLeastUs(I2S_TX_ONE_SAMPLE_MAX_TIMEOUT, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
189 }
190
191 /* The last piece of valid data can be still being transmitted from I2S at this moment */
192 timeout = I2S_TX_ONE_SAMPLE_MAX_TIMEOUT;
193 /* Write additional data to FIFO */
194 base->FIFOWR = 0U;
195 while (((base->FIFOSTAT & I2S_FIFOSTAT_TXEMPTY_MASK) == 0U) && (timeout != 0U))
196 {
197 timeout -= I2S_TX_ONE_SAMPLE_MAX_TIMEOUT;
198 SDK_DelayAtLeastUs(I2S_TX_ONE_SAMPLE_MAX_TIMEOUT, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
199 }
200
201 return ((base->FIFOSTAT & I2S_FIFOSTAT_TXEMPTY_MASK) == 0U) ? kStatus_Fail : kStatus_Success;
202 }
203
204 /*!
205 * brief Sets the I2S Tx configuration structure to default values.
206 *
207 * This API initializes the configuration structure for use in I2S_TxInit().
208 * The initialized structure can remain unchanged in I2S_TxInit(), or it can be modified
209 * before calling I2S_TxInit().
210 * Example:
211 code
212 i2s_config_t config;
213 I2S_TxGetDefaultConfig(&config);
214 endcode
215 *
216 * Default values:
217 * code
218 * config->masterSlave = kI2S_MasterSlaveNormalMaster;
219 * config->mode = kI2S_ModeI2sClassic;
220 * config->rightLow = false;
221 * config->leftJust = false;
222 * config->pdmData = false;
223 * config->sckPol = false;
224 * config->wsPol = false;
225 * config->divider = 1;
226 * config->oneChannel = false;
227 * config->dataLength = 16;
228 * config->frameLength = 32;
229 * config->position = 0;
230 * config->watermark = 4;
231 * config->txEmptyZero = true;
232 * config->pack48 = false;
233 * endcode
234 *
235 * param config pointer to I2S configuration structure.
236 */
I2S_TxGetDefaultConfig(i2s_config_t * config)237 void I2S_TxGetDefaultConfig(i2s_config_t *config)
238 {
239 config->masterSlave = kI2S_MasterSlaveNormalMaster;
240 config->mode = kI2S_ModeI2sClassic;
241 config->rightLow = false;
242 config->leftJust = false;
243 #if (defined(FSL_FEATURE_FLEXCOMM_I2S_HAS_DMIC_INTERCONNECTION) && FSL_FEATURE_FLEXCOMM_I2S_HAS_DMIC_INTERCONNECTION)
244 config->pdmData = false;
245 #endif
246 config->sckPol = false;
247 config->wsPol = false;
248 config->divider = 1U;
249 config->oneChannel = false;
250 config->dataLength = 16U;
251 config->frameLength = 32U;
252 config->position = 0U;
253 config->watermark = 4U;
254 config->txEmptyZero = true;
255 config->pack48 = false;
256 }
257
258 /*!
259 * brief Sets the I2S Rx configuration structure to default values.
260 *
261 * This API initializes the configuration structure for use in I2S_RxInit().
262 * The initialized structure can remain unchanged in I2S_RxInit(), or it can be modified
263 * before calling I2S_RxInit().
264 * Example:
265 code
266 i2s_config_t config;
267 I2S_RxGetDefaultConfig(&config);
268 endcode
269 *
270 * Default values:
271 * code
272 * config->masterSlave = kI2S_MasterSlaveNormalSlave;
273 * config->mode = kI2S_ModeI2sClassic;
274 * config->rightLow = false;
275 * config->leftJust = false;
276 * config->pdmData = false;
277 * config->sckPol = false;
278 * config->wsPol = false;
279 * config->divider = 1;
280 * config->oneChannel = false;
281 * config->dataLength = 16;
282 * config->frameLength = 32;
283 * config->position = 0;
284 * config->watermark = 4;
285 * config->txEmptyZero = false;
286 * config->pack48 = false;
287 * endcode
288 *
289 * param config pointer to I2S configuration structure.
290 */
I2S_RxGetDefaultConfig(i2s_config_t * config)291 void I2S_RxGetDefaultConfig(i2s_config_t *config)
292 {
293 config->masterSlave = kI2S_MasterSlaveNormalSlave;
294 config->mode = kI2S_ModeI2sClassic;
295 config->rightLow = false;
296 config->leftJust = false;
297 #if (defined(FSL_FEATURE_FLEXCOMM_I2S_HAS_DMIC_INTERCONNECTION) && FSL_FEATURE_FLEXCOMM_I2S_HAS_DMIC_INTERCONNECTION)
298 config->pdmData = false;
299 #endif
300 config->sckPol = false;
301 config->wsPol = false;
302 config->divider = 1U;
303 config->oneChannel = false;
304 config->dataLength = 16U;
305 config->frameLength = 32U;
306 config->position = 0U;
307 config->watermark = 4U;
308 config->txEmptyZero = false;
309 config->pack48 = false;
310 }
311
I2S_Config(I2S_Type * base,const i2s_config_t * config)312 static void I2S_Config(I2S_Type *base, const i2s_config_t *config)
313 {
314 assert(config != NULL);
315
316 uint32_t cfg1 = 0U;
317 uint32_t cfg2 = 0U;
318
319 /* set master/slave configuration */
320 cfg1 |= I2S_CFG1_MSTSLVCFG(config->masterSlave);
321
322 /* set I2S mode */
323 cfg1 |= I2S_CFG1_MODE(config->mode);
324
325 /* set right low (channel swap) */
326 cfg1 |= I2S_CFG1_RIGHTLOW(config->rightLow);
327
328 /* set data justification */
329 cfg1 |= I2S_CFG1_LEFTJUST(config->leftJust);
330
331 #if (defined(FSL_FEATURE_FLEXCOMM_I2S_HAS_DMIC_INTERCONNECTION) && FSL_FEATURE_FLEXCOMM_I2S_HAS_DMIC_INTERCONNECTION)
332 if (FSL_FEATURE_FLEXCOMM_INSTANCE_I2S_HAS_DMIC_INTERCONNECTIONn((FLEXCOMM_Type *)(uint32_t)base) > 0)
333 {
334 /* set source to PDM dmic */
335 cfg1 |= I2S_CFG1_PDMDATA(config->pdmData);
336 }
337 #endif
338
339 /* set SCLK polarity */
340 cfg1 |= I2S_CFG1_SCK_POL(config->sckPol);
341
342 /* set WS polarity */
343 cfg1 |= I2S_CFG1_WS_POL(config->wsPol);
344
345 /* set mono mode */
346 cfg1 |= I2S_CFG1_ONECHANNEL(config->oneChannel);
347
348 /* set data length */
349 cfg1 |= I2S_CFG1_DATALEN(config->dataLength - 1UL);
350
351 /* set frame length */
352 cfg2 |= I2S_CFG2_FRAMELEN(config->frameLength - 1UL);
353
354 /* set data position of this channel pair within the frame */
355 cfg2 |= I2S_CFG2_POSITION(config->position);
356
357 /* write to registers */
358 base->CFG1 = cfg1;
359 base->CFG2 = cfg2;
360
361 /* set the clock divider */
362 base->DIV = I2S_DIV_DIV(config->divider - 1UL);
363 }
364
365 /*!
366 * brief De-initializes the I2S peripheral.
367 *
368 * This API gates the FLEXCOMM clock. The I2S module can't operate unless I2S_TxInit
369 * or I2S_RxInit is called to enable the clock.
370 *
371 * param base I2S base pointer.
372 */
I2S_Deinit(I2S_Type * base)373 void I2S_Deinit(I2S_Type *base)
374 {
375 /* TODO gate FLEXCOMM clock via FLEXCOMM driver */
376 }
377
I2S_TxEnable(I2S_Type * base,bool enable)378 static void I2S_TxEnable(I2S_Type *base, bool enable)
379 {
380 if (enable)
381 {
382 I2S_Enable(base);
383 I2S_EnableInterrupts(base, (uint32_t)kI2S_TxErrorFlag | (uint32_t)kI2S_TxLevelFlag);
384 }
385 else
386 {
387 I2S_DisableInterrupts(base, (uint32_t)kI2S_TxErrorFlag | (uint32_t)kI2S_TxLevelFlag);
388 I2S_Disable(base);
389 base->FIFOCFG |= I2S_FIFOCFG_EMPTYTX_MASK;
390 }
391 }
392
I2S_RxEnable(I2S_Type * base,bool enable)393 static void I2S_RxEnable(I2S_Type *base, bool enable)
394 {
395 if (enable)
396 {
397 I2S_Enable(base);
398 I2S_EnableInterrupts(base, (uint32_t)kI2S_RxErrorFlag | (uint32_t)kI2S_RxLevelFlag);
399 }
400 else
401 {
402 I2S_DisableInterrupts(base, (uint32_t)kI2S_RxErrorFlag | (uint32_t)kI2S_RxLevelFlag);
403 I2S_Disable(base);
404 base->FIFOCFG |= I2S_FIFOCFG_EMPTYRX_MASK;
405 }
406 }
407
I2S_ValidateBuffer(i2s_handle_t * handle,i2s_transfer_t * transfer)408 static status_t I2S_ValidateBuffer(i2s_handle_t *handle, i2s_transfer_t *transfer)
409 {
410 assert(transfer->data != NULL);
411
412 if (transfer->data == NULL)
413 {
414 return kStatus_InvalidArgument;
415 }
416
417 assert(transfer->dataSize > 0U);
418 if (transfer->dataSize <= 0U)
419 {
420 return kStatus_InvalidArgument;
421 }
422
423 if (handle->dataLength == 4U)
424 {
425 /* No alignment and data length requirements */
426 }
427 else if ((handle->dataLength >= 5U) && (handle->dataLength <= 8U))
428 {
429 assert((((uint32_t)transfer->data) % 2U) == 0U);
430 if ((((uint32_t)transfer->data) % 2U) != 0U)
431 {
432 /* Data not 2-bytes aligned */
433 return kStatus_InvalidArgument;
434 }
435
436 assert((transfer->dataSize % 2U) == 0U);
437 if ((transfer->dataSize % 2U) != 0U)
438 {
439 /* Data not in pairs of left/right channel bytes */
440 return kStatus_InvalidArgument;
441 }
442 }
443 else if ((handle->dataLength >= 9U) && (handle->dataLength <= 16U))
444 {
445 assert((((uint32_t)transfer->data) % 4U) == 0U);
446 if ((((uint32_t)transfer->data) % 4U) != 0U)
447 {
448 /* Data not 4-bytes aligned */
449 return kStatus_InvalidArgument;
450 }
451
452 assert((transfer->dataSize % 4U) == 0U);
453 if ((transfer->dataSize % 4U) != 0U)
454 {
455 /* Data lenght not multiply of 4 */
456 return kStatus_InvalidArgument;
457 }
458 }
459 else if ((handle->dataLength >= 17U) && (handle->dataLength <= 24U))
460 {
461 assert((transfer->dataSize % 6U) == 0U);
462 if ((transfer->dataSize % 6U) != 0U)
463 {
464 /* Data lenght not multiply of 6 */
465 return kStatus_InvalidArgument;
466 }
467
468 assert(!((handle->pack48) && ((((uint32_t)transfer->data) % 4U) != 0U)));
469 if ((handle->pack48) && ((((uint32_t)transfer->data) % 4U) != 0U))
470 {
471 /* Data not 4-bytes aligned */
472 return kStatus_InvalidArgument;
473 }
474 }
475 else /* if (handle->dataLength >= 25U) */
476 {
477 assert((((uint32_t)transfer->data) % 4U) == 0U);
478 if ((((uint32_t)transfer->data) % 4U) != 0U)
479 {
480 /* Data not 4-bytes aligned */
481 return kStatus_InvalidArgument;
482 }
483
484 if (handle->oneChannel)
485 {
486 assert((transfer->dataSize % 4U) == 0U);
487 if ((transfer->dataSize % 4U) != 0U)
488 {
489 /* Data lenght not multiply of 4 */
490 return kStatus_InvalidArgument;
491 }
492 }
493 else
494 {
495 assert((transfer->dataSize % 8U) == 0U);
496 if ((transfer->dataSize % 8U) != 0U)
497 {
498 /* Data lenght not multiply of 8 */
499 return kStatus_InvalidArgument;
500 }
501 }
502 }
503
504 return kStatus_Success;
505 }
506
507 #if (defined(FSL_FEATURE_I2S_SUPPORT_SECONDARY_CHANNEL) && FSL_FEATURE_I2S_SUPPORT_SECONDARY_CHANNEL)
508 /*!
509 * brief Enables I2S secondary channel.
510 *
511 * param base I2S base pointer.
512 * param channel seondary channel channel number, reference _i2s_secondary_channel.
513 * param oneChannel true is treated as single channel, functionality left channel for this pair.
514 * param position define the location within the frame of the data, should not bigger than 0x1FFU.
515 */
I2S_EnableSecondaryChannel(I2S_Type * base,uint32_t channel,bool oneChannel,uint32_t position)516 void I2S_EnableSecondaryChannel(I2S_Type *base, uint32_t channel, bool oneChannel, uint32_t position)
517 {
518 assert(channel <= (uint32_t)kI2S_SecondaryChannel3);
519 #if defined FSL_FEATURE_FLEXCOMM_INSTANCE_I2S_SUPPORT_SECONDARY_CHANNELn
520 assert(FSL_FEATURE_FLEXCOMM_INSTANCE_I2S_SUPPORT_SECONDARY_CHANNELn((FLEXCOMM_Type *)(uint32_t)base) == 1);
521 #endif
522
523 uint32_t pcfg1 = base->SECCHANNEL[channel].PCFG1;
524 uint32_t pcfg2 = base->SECCHANNEL[channel].PCFG2;
525
526 pcfg1 &= ~I2S_CFG1_ONECHANNEL_MASK;
527 pcfg1 |= I2S_CFG1_MAINENABLE_MASK | I2S_CFG1_ONECHANNEL(oneChannel);
528
529 pcfg2 &= ~I2S_CFG2_POSITION_MASK;
530 pcfg2 |= I2S_CFG2_POSITION(position);
531
532 base->SECCHANNEL[channel].PCFG1 = pcfg1;
533 base->SECCHANNEL[channel].PCFG2 = pcfg2;
534 }
535 #endif
536
537 /*!
538 * brief Initializes handle for transfer of audio data.
539 *
540 * param base I2S base pointer.
541 * param handle pointer to handle structure.
542 * param callback function to be called back when transfer is done or fails.
543 * param userData pointer to data passed to callback.
544 */
I2S_TxTransferCreateHandle(I2S_Type * base,i2s_handle_t * handle,i2s_transfer_callback_t callback,void * userData)545 void I2S_TxTransferCreateHandle(I2S_Type *base, i2s_handle_t *handle, i2s_transfer_callback_t callback, void *userData)
546 {
547 assert(handle != NULL);
548
549 uint32_t instance;
550
551 /* Clear out the handle */
552 (void)memset(handle, 0, sizeof(*handle));
553
554 /* Look up instance number */
555 instance = I2S_GetInstance(base);
556
557 /* Save callback and user data */
558 handle->completionCallback = callback;
559 handle->userData = userData;
560
561 /* Remember some items set previously by configuration */
562 handle->watermark = (uint8_t)((base->FIFOTRIG & I2S_FIFOTRIG_TXLVL_MASK) >> I2S_FIFOTRIG_TXLVL_SHIFT);
563 handle->oneChannel = ((base->CFG1 & I2S_CFG1_ONECHANNEL_MASK) >> I2S_CFG1_ONECHANNEL_SHIFT) != 0U ? true : false;
564 handle->dataLength = (uint8_t)((base->CFG1 & I2S_CFG1_DATALEN_MASK) >> I2S_CFG1_DATALEN_SHIFT) + 1U;
565 handle->pack48 = ((base->FIFOCFG & I2S_FIFOCFG_PACK48_MASK) >> I2S_FIFOCFG_PACK48_SHIFT) != 0u ? true : false;
566
567 handle->useFifo48H = false;
568
569 /* Register IRQ handling */
570 FLEXCOMM_SetIRQHandler(base, (flexcomm_irq_handler_t)I2S_TxHandleIRQ, handle);
571 /* Clear internal IRQ enables and enable NVIC IRQ. */
572 I2S_DisableInterrupts(base, (uint32_t)kI2S_TxErrorFlag | (uint32_t)kI2S_TxLevelFlag);
573 (void)EnableIRQ(s_i2sIRQ[instance]);
574 }
575
576 /*!
577 * brief Begins or queue sending of the given data.
578 *
579 * param base I2S base pointer.
580 * param handle pointer to handle structure.
581 * param transfer data buffer.
582 *
583 * retval kStatus_Success
584 * retval kStatus_I2S_Busy if all queue slots are occupied with unsent buffers.
585 */
I2S_TxTransferNonBlocking(I2S_Type * base,i2s_handle_t * handle,i2s_transfer_t transfer)586 status_t I2S_TxTransferNonBlocking(I2S_Type *base, i2s_handle_t *handle, i2s_transfer_t transfer)
587 {
588 assert(handle != NULL);
589
590 status_t result;
591
592 if (handle == NULL)
593 {
594 return kStatus_InvalidArgument;
595 }
596
597 result = I2S_ValidateBuffer(handle, &transfer);
598 if (result != kStatus_Success)
599 {
600 return result;
601 }
602
603 if (handle->i2sQueue[handle->queueUser].dataSize != 0UL)
604 {
605 /* Previously prepared buffers not processed yet */
606 return kStatus_I2S_Busy;
607 }
608
609 handle->i2sQueue[handle->queueUser].data = transfer.data;
610 handle->i2sQueue[handle->queueUser].dataSize = transfer.dataSize;
611 handle->queueUser = (handle->queueUser + 1U) % I2S_NUM_BUFFERS;
612
613 base->FIFOTRIG = (base->FIFOTRIG & (~I2S_FIFOTRIG_TXLVL_MASK)) | I2S_FIFOTRIG_TXLVL(handle->watermark);
614 I2S_TxEnable(base, true);
615
616 return kStatus_Success;
617 }
618
619 /*!
620 * brief Aborts sending of data.
621 *
622 * param base I2S base pointer.
623 * param handle pointer to handle structure.
624 */
I2S_TxTransferAbort(I2S_Type * base,i2s_handle_t * handle)625 void I2S_TxTransferAbort(I2S_Type *base, i2s_handle_t *handle)
626 {
627 assert(handle != NULL);
628
629 /* Disable I2S operation and interrupts */
630 I2S_TxEnable(base, false);
631
632 /* Reset state */
633 handle->state = (uint32_t)kI2S_StateIdle;
634
635 /* Clear transfer queue */
636 (void)memset((void *)&handle->i2sQueue, 0, sizeof(i2s_transfer_t) * I2S_NUM_BUFFERS);
637 handle->queueDriver = 0U;
638 handle->queueUser = 0U;
639 }
640
641 /*!
642 * brief Initializes handle for reception of audio data.
643 *
644 * param base I2S base pointer.
645 * param handle pointer to handle structure.
646 * param callback function to be called back when transfer is done or fails.
647 * param userData pointer to data passed to callback.
648 */
I2S_RxTransferCreateHandle(I2S_Type * base,i2s_handle_t * handle,i2s_transfer_callback_t callback,void * userData)649 void I2S_RxTransferCreateHandle(I2S_Type *base, i2s_handle_t *handle, i2s_transfer_callback_t callback, void *userData)
650 {
651 assert(handle != NULL);
652
653 uint32_t instance;
654
655 /* Clear out the handle */
656 (void)memset(handle, 0, sizeof(*handle));
657
658 /* Look up instance number */
659 instance = I2S_GetInstance(base);
660
661 /* Save callback and user data */
662 handle->completionCallback = callback;
663 handle->userData = userData;
664
665 /* Remember some items set previously by configuration */
666 handle->watermark = (uint8_t)((base->FIFOTRIG & I2S_FIFOTRIG_RXLVL_MASK) >> I2S_FIFOTRIG_RXLVL_SHIFT);
667 handle->oneChannel = ((base->CFG1 & I2S_CFG1_ONECHANNEL_MASK) >> I2S_CFG1_ONECHANNEL_SHIFT) != 0UL ? true : false;
668 handle->dataLength = (uint8_t)((base->CFG1 & I2S_CFG1_DATALEN_MASK) >> I2S_CFG1_DATALEN_SHIFT) + 1U;
669 handle->pack48 = ((base->FIFOCFG & I2S_FIFOCFG_PACK48_MASK) >> I2S_FIFOCFG_PACK48_SHIFT) != 0UL ? true : false;
670
671 handle->useFifo48H = false;
672
673 /* Register IRQ handling */
674 FLEXCOMM_SetIRQHandler(base, (flexcomm_irq_handler_t)I2S_RxHandleIRQ, handle);
675 /* Clear internal IRQ enables and enable NVIC IRQ. */
676 I2S_DisableInterrupts(base, (uint32_t)kI2S_RxErrorFlag | (uint32_t)kI2S_RxLevelFlag);
677
678 (void)EnableIRQ(s_i2sIRQ[instance]);
679 }
680
681 /*!
682 * brief Begins or queue reception of data into given buffer.
683 *
684 * param base I2S base pointer.
685 * param handle pointer to handle structure.
686 * param transfer data buffer.
687 *
688 * retval kStatus_Success
689 * retval kStatus_I2S_Busy if all queue slots are occupied with buffers which are not full.
690 */
I2S_RxTransferNonBlocking(I2S_Type * base,i2s_handle_t * handle,i2s_transfer_t transfer)691 status_t I2S_RxTransferNonBlocking(I2S_Type *base, i2s_handle_t *handle, i2s_transfer_t transfer)
692 {
693 assert(handle != NULL);
694
695 status_t result;
696
697 if (NULL == handle)
698 {
699 return kStatus_InvalidArgument;
700 }
701
702 result = I2S_ValidateBuffer(handle, &transfer);
703 if (result != kStatus_Success)
704 {
705 return result;
706 }
707
708 if (handle->i2sQueue[handle->queueUser].dataSize != 0UL)
709 {
710 /* Previously prepared buffers not processed yet */
711 return kStatus_I2S_Busy;
712 }
713
714 handle->i2sQueue[handle->queueUser].data = transfer.data;
715 handle->i2sQueue[handle->queueUser].dataSize = transfer.dataSize;
716 handle->queueUser = (handle->queueUser + 1U) % I2S_NUM_BUFFERS;
717
718 base->FIFOTRIG = (base->FIFOTRIG & (~I2S_FIFOTRIG_RXLVL_MASK)) | I2S_FIFOTRIG_RXLVL(handle->watermark);
719 I2S_RxEnable(base, true);
720
721 return kStatus_Success;
722 }
723
724 /*!
725 * brief Aborts receiving of data.
726 *
727 * param base I2S base pointer.
728 * param handle pointer to handle structure.
729 */
I2S_RxTransferAbort(I2S_Type * base,i2s_handle_t * handle)730 void I2S_RxTransferAbort(I2S_Type *base, i2s_handle_t *handle)
731 {
732 assert(handle != NULL);
733
734 /* Disable I2S operation and interrupts */
735 I2S_RxEnable(base, false);
736
737 /* Reset state */
738 handle->state = (uint32_t)kI2S_StateIdle;
739
740 /* Clear transfer queue */
741 (void)memset((void *)&handle->i2sQueue, 0, sizeof(i2s_transfer_t) * I2S_NUM_BUFFERS);
742 handle->queueDriver = 0U;
743 handle->queueUser = 0U;
744 }
745
746 /*!
747 * brief Returns number of bytes transferred so far.
748 *
749 * param base I2S base pointer.
750 * param handle pointer to handle structure.
751 * param[out] count number of bytes transferred so far by the non-blocking transaction.
752 *
753 * retval kStatus_Success
754 * retval kStatus_NoTransferInProgress there is no non-blocking transaction currently in progress.
755 */
I2S_TransferGetCount(I2S_Type * base,i2s_handle_t * handle,size_t * count)756 status_t I2S_TransferGetCount(I2S_Type *base, i2s_handle_t *handle, size_t *count)
757 {
758 assert(handle != NULL);
759 assert(count != NULL);
760
761 if (NULL == handle)
762 {
763 return kStatus_InvalidArgument;
764 }
765
766 if (NULL == count)
767 {
768 return kStatus_InvalidArgument;
769 }
770
771 if (handle->state == (uint32_t)kI2S_StateIdle)
772 {
773 return kStatus_NoTransferInProgress;
774 }
775
776 *count = handle->transferCount;
777
778 return kStatus_Success;
779 }
780
781 /*!
782 * brief Returns number of buffer underruns or overruns.
783 *
784 * param base I2S base pointer.
785 * param handle pointer to handle structure.
786 * param[out] count number of transmit errors encountered so far by the non-blocking transaction.
787 *
788 * retval kStatus_Success
789 * retval kStatus_NoTransferInProgress there is no non-blocking transaction currently in progress.
790 */
I2S_TransferGetErrorCount(I2S_Type * base,i2s_handle_t * handle,size_t * count)791 status_t I2S_TransferGetErrorCount(I2S_Type *base, i2s_handle_t *handle, size_t *count)
792 {
793 assert(handle != NULL);
794 assert(count != NULL);
795
796 if (NULL == handle)
797 {
798 return kStatus_InvalidArgument;
799 }
800
801 if (NULL == count)
802 {
803 return kStatus_InvalidArgument;
804 }
805
806 if (handle->state == (uint32_t)kI2S_StateIdle)
807 {
808 return kStatus_NoTransferInProgress;
809 }
810
811 *count = handle->errorCount;
812
813 return kStatus_Success;
814 }
815
816 /*!
817 * brief Invoked from interrupt handler when transmit FIFO level decreases.
818 *
819 * param base I2S base pointer.
820 * param handle pointer to handle structure.
821 */
I2S_TxHandleIRQ(I2S_Type * base,i2s_handle_t * handle)822 void I2S_TxHandleIRQ(I2S_Type *base, i2s_handle_t *handle)
823 {
824 uint32_t intstat = base->FIFOINTSTAT;
825 uint32_t data;
826 uint8_t queueDriverIndex = handle->queueDriver;
827 uint32_t dataAddr = (uint32_t)handle->i2sQueue[queueDriverIndex].data;
828 uint32_t dataSize = handle->i2sQueue[queueDriverIndex].dataSize;
829
830 if ((intstat & I2S_FIFOINTSTAT_TXERR_MASK) != 0UL)
831 {
832 handle->errorCount++;
833
834 /* Clear TX error interrupt flag */
835 base->FIFOSTAT = I2S_FIFOSTAT_TXERR(1U);
836 }
837
838 if ((intstat & I2S_FIFOINTSTAT_TXLVL_MASK) != 0UL)
839 {
840 if ((handle->state != (uint32_t)kI2S_StateTx) && (dataSize != 0U) && (dataAddr != 0U))
841 {
842 handle->state = (uint32_t)kI2S_StateTx;
843 }
844
845 if (handle->state == (uint32_t)kI2S_StateTx)
846 {
847 /* Send data */
848
849 while (((base->FIFOSTAT & I2S_FIFOSTAT_TXNOTFULL_MASK) != 0UL) && (dataSize > 0U))
850 {
851 /* Write output data */
852 if (handle->dataLength == 4U)
853 {
854 data = *((uint8_t *)dataAddr);
855 base->FIFOWR = ((data & 0xF0U) << 12U) | (data & 0xFU);
856 dataAddr++;
857 handle->transferCount++;
858 dataSize--;
859 }
860 else if (handle->dataLength <= 8U)
861 {
862 data = *((volatile uint16_t *)dataAddr);
863 if (handle->oneChannel)
864 {
865 base->FIFOWR = (data & 0xFFU);
866 dataAddr += sizeof(uint8_t);
867 handle->transferCount += sizeof(uint8_t);
868 dataSize -= sizeof(uint8_t);
869 }
870 else
871 {
872 base->FIFOWR = ((data & 0xFF00U) << 8U) | (data & 0xFFU);
873 dataAddr += sizeof(uint16_t);
874 handle->transferCount += sizeof(uint16_t);
875 dataSize -= sizeof(uint16_t);
876 }
877 }
878 else if (handle->dataLength <= 16U)
879 {
880 data = *((volatile uint32_t *)(dataAddr));
881 if (handle->oneChannel)
882 {
883 base->FIFOWR = data & 0xFFFFU;
884 dataAddr += sizeof(uint16_t);
885 handle->transferCount += sizeof(uint16_t);
886 dataSize -= sizeof(uint16_t);
887 }
888 else
889 {
890 base->FIFOWR = data;
891 dataAddr += sizeof(uint32_t);
892 handle->transferCount += sizeof(uint32_t);
893 dataSize -= sizeof(uint32_t);
894 }
895 }
896 else if (handle->dataLength <= 24U)
897 {
898 if (handle->pack48)
899 {
900 if (handle->useFifo48H)
901 {
902 base->FIFOWR48H = *((volatile uint16_t *)(dataAddr));
903 dataAddr += sizeof(uint16_t);
904 handle->transferCount += sizeof(uint16_t);
905 dataSize -= sizeof(uint16_t);
906 handle->useFifo48H = false;
907 }
908 else
909 {
910 base->FIFOWR = *((volatile uint32_t *)(dataAddr));
911 dataAddr += sizeof(uint32_t);
912 handle->transferCount += sizeof(uint32_t);
913 dataSize -= sizeof(uint32_t);
914 handle->useFifo48H = true;
915 }
916 }
917 else
918 {
919 data = (uint32_t)(*(uint8_t *)(dataAddr++));
920 data |= ((uint32_t)(*(uint8_t *)(dataAddr++))) << 8U;
921 data |= ((uint32_t)(*(uint8_t *)(dataAddr++))) << 16U;
922 if ((handle->useFifo48H) && (handle->oneChannel == false))
923 {
924 base->FIFOWR48H = data;
925 handle->useFifo48H = false;
926 }
927 else
928 {
929 base->FIFOWR = data;
930 handle->useFifo48H = true;
931 }
932 handle->transferCount += 3U;
933 dataSize -= 3U;
934 }
935 }
936 else /* if (handle->dataLength <= 32U) */
937 {
938 base->FIFOWR = *((volatile uint32_t *)(dataAddr));
939 dataAddr += sizeof(uint32_t);
940 handle->transferCount += sizeof(uint32_t);
941 dataSize -= sizeof(uint32_t);
942 }
943
944 if (dataSize == 0U)
945 {
946 handle->i2sQueue[queueDriverIndex].dataSize = 0U;
947 /* Actual data buffer sent out, switch to a next one */
948 handle->queueDriver = (queueDriverIndex + 1U) % I2S_NUM_BUFFERS;
949
950 /* Notify user */
951 if (handle->completionCallback != NULL)
952 {
953 handle->completionCallback(base, handle, kStatus_I2S_BufferComplete, handle->userData);
954 }
955
956 /* Check if the next buffer contains anything to send */
957 if (handle->i2sQueue[handle->queueDriver].dataSize == 0U)
958 {
959 /* Everything has been written to FIFO */
960 handle->state = kI2S_StateTxWaitToWriteDummyData;
961 break;
962 }
963 }
964 else
965 {
966 handle->i2sQueue[queueDriverIndex].dataSize = dataSize;
967 handle->i2sQueue[queueDriverIndex].data = (uint8_t *)dataAddr;
968 }
969 }
970 }
971 else if (handle->state == (uint32_t)kI2S_StateTxWaitToWriteDummyData)
972 {
973 /* Write dummy data */
974 if ((handle->dataLength > 16U) && (handle->dataLength < 25U))
975 {
976 if (handle->useFifo48H)
977 {
978 base->FIFOWR48H = 0U;
979 handle->useFifo48H = false;
980 }
981 else
982 {
983 base->FIFOWR = 0U;
984 base->FIFOWR48H = 0U;
985 }
986 }
987 else
988 {
989 base->FIFOWR = 0U;
990 }
991
992 /* Next time invoke this handler when FIFO becomes empty (TX level 0) */
993 base->FIFOTRIG &= ~I2S_FIFOTRIG_TXLVL_MASK;
994 handle->state = (uint32_t)kI2S_StateTxWaitForEmptyFifo;
995 }
996 else if (handle->state == (uint32_t)kI2S_StateTxWaitForEmptyFifo)
997 {
998 /* FIFO, including additional dummy data, has been emptied now,
999 * all relevant data should have been output from peripheral */
1000
1001 /* Stop transfer */
1002 I2S_Disable(base);
1003 I2S_DisableInterrupts(base, (uint32_t)kI2S_TxErrorFlag | (uint32_t)kI2S_TxLevelFlag);
1004 base->FIFOCFG |= I2S_FIFOCFG_EMPTYTX_MASK;
1005
1006 /* Reset state */
1007 handle->state = (uint32_t)kI2S_StateIdle;
1008
1009 /* Notify user */
1010 if (handle->completionCallback != NULL)
1011 {
1012 handle->completionCallback(base, handle, kStatus_I2S_Done, handle->userData);
1013 }
1014 }
1015 else
1016 {
1017 /* Do nothing */
1018 }
1019
1020 /* Clear TX level interrupt flag */
1021 base->FIFOSTAT = I2S_FIFOSTAT_TXLVL(1U);
1022 }
1023 }
1024
1025 /*!
1026 * brief Invoked from interrupt handler when receive FIFO level decreases.
1027 *
1028 * param base I2S base pointer.
1029 * param handle pointer to handle structure.
1030 */
I2S_RxHandleIRQ(I2S_Type * base,i2s_handle_t * handle)1031 void I2S_RxHandleIRQ(I2S_Type *base, i2s_handle_t *handle)
1032 {
1033 uint32_t intstat = base->FIFOINTSTAT;
1034 uint32_t data;
1035 uint8_t queueDriverIndex = handle->queueDriver;
1036 uint32_t dataAddr = (uint32_t)handle->i2sQueue[queueDriverIndex].data;
1037 uint32_t dataSize = handle->i2sQueue[queueDriverIndex].dataSize;
1038
1039 if ((intstat & I2S_FIFOINTSTAT_RXERR_MASK) != 0UL)
1040 {
1041 handle->errorCount++;
1042
1043 /* Clear RX error interrupt flag */
1044 base->FIFOSTAT = I2S_FIFOSTAT_RXERR(1U);
1045 }
1046
1047 if ((intstat & I2S_FIFOINTSTAT_RXLVL_MASK) != 0UL)
1048 {
1049 while (((base->FIFOSTAT & I2S_FIFOSTAT_RXNOTEMPTY_MASK) != 0UL) && (dataSize > 0U))
1050 {
1051 /* Read input data */
1052 if (handle->dataLength == 4U)
1053 {
1054 data = base->FIFORD;
1055 *((uint8_t *)dataAddr) = (uint8_t)(((data & 0x000F0000U) >> 12U) | (data & 0x0000000FU));
1056 dataAddr++;
1057 handle->transferCount++;
1058 dataSize--;
1059 }
1060 else if (handle->dataLength <= 8U)
1061 {
1062 data = base->FIFORD;
1063
1064 if (handle->oneChannel)
1065 {
1066 *((volatile uint8_t *)dataAddr) = (uint8_t)(data & 0xFFU);
1067 dataAddr += sizeof(uint8_t);
1068 handle->transferCount += sizeof(uint8_t);
1069 dataSize -= sizeof(uint8_t);
1070 }
1071 else
1072 {
1073 *((volatile uint16_t *)dataAddr) = (uint16_t)(((data >> 8U) & 0xFF00U) | (data & 0xFFU));
1074 dataAddr += sizeof(uint16_t);
1075 handle->transferCount += sizeof(uint16_t);
1076 dataSize -= sizeof(uint16_t);
1077 }
1078 }
1079 else if (handle->dataLength <= 16U)
1080 {
1081 data = base->FIFORD;
1082
1083 if (handle->oneChannel)
1084 {
1085 *((volatile uint16_t *)dataAddr) = (uint16_t)(data & 0xFFFFU);
1086 dataAddr += sizeof(uint16_t);
1087 handle->transferCount += sizeof(uint16_t);
1088 dataSize -= sizeof(uint16_t);
1089 }
1090 else
1091 {
1092 *((volatile uint32_t *)dataAddr) = data;
1093 dataAddr += sizeof(uint32_t);
1094 handle->transferCount += sizeof(uint32_t);
1095 dataSize -= sizeof(uint32_t);
1096 }
1097 }
1098 else if (handle->dataLength <= 24U)
1099 {
1100 if (handle->pack48)
1101 {
1102 if (handle->useFifo48H)
1103 {
1104 data = base->FIFORD48H;
1105 handle->useFifo48H = false;
1106
1107 *((volatile uint16_t *)dataAddr) = (uint16_t)data;
1108 dataAddr += sizeof(uint16_t);
1109 handle->transferCount += sizeof(uint16_t);
1110 dataSize -= sizeof(uint16_t);
1111 }
1112 else
1113 {
1114 data = base->FIFORD;
1115 handle->useFifo48H = true;
1116
1117 *((volatile uint32_t *)dataAddr) = data;
1118 dataAddr += sizeof(uint32_t);
1119 handle->transferCount += sizeof(uint32_t);
1120 dataSize -= sizeof(uint32_t);
1121 }
1122 }
1123 else
1124 {
1125 if (handle->useFifo48H)
1126 {
1127 data = base->FIFORD48H;
1128 handle->useFifo48H = false;
1129 }
1130 else
1131 {
1132 data = base->FIFORD;
1133 handle->useFifo48H = true;
1134 }
1135
1136 *(uint8_t *)(dataAddr++) = (uint8_t)(data & 0xFFU);
1137 *(uint8_t *)(dataAddr++) = (uint8_t)((data >> 8U) & 0xFFU);
1138 *(uint8_t *)(dataAddr++) = (uint8_t)((data >> 16U) & 0xFFU);
1139 handle->transferCount += 3U;
1140 dataSize -= 3U;
1141 }
1142 }
1143 else /* if (handle->dataLength <= 32U) */
1144 {
1145 data = base->FIFORD;
1146 *((volatile uint32_t *)dataAddr) = data;
1147 dataAddr += sizeof(uint32_t);
1148 handle->transferCount += sizeof(uint32_t);
1149 dataSize -= sizeof(uint32_t);
1150 }
1151
1152 if (dataSize == 0U)
1153 {
1154 handle->i2sQueue[queueDriverIndex].dataSize = 0U;
1155 /* Actual data buffer filled with input data, switch to a next one */
1156 handle->queueDriver = (queueDriverIndex + 1U) % I2S_NUM_BUFFERS;
1157
1158 /* Notify user */
1159 if (handle->completionCallback != NULL)
1160 {
1161 handle->completionCallback(base, handle, kStatus_I2S_BufferComplete, handle->userData);
1162 }
1163
1164 if (handle->i2sQueue[handle->queueDriver].dataSize == 0U)
1165 {
1166 /* No other buffer prepared to receive data into */
1167
1168 /* Disable I2S operation and interrupts */
1169 I2S_Disable(base);
1170 I2S_DisableInterrupts(base, (uint32_t)kI2S_RxErrorFlag | (uint32_t)kI2S_RxLevelFlag);
1171 base->FIFOCFG |= I2S_FIFOCFG_EMPTYRX_MASK;
1172
1173 /* Reset state */
1174 handle->state = (uint32_t)kI2S_StateIdle;
1175
1176 /* Notify user */
1177 if (handle->completionCallback != NULL)
1178 {
1179 handle->completionCallback(base, handle, kStatus_I2S_Done, handle->userData);
1180 }
1181
1182 /* Clear RX level interrupt flag */
1183 base->FIFOSTAT = I2S_FIFOSTAT_RXLVL(1U);
1184
1185 return;
1186 }
1187 }
1188 else
1189 {
1190 handle->i2sQueue[queueDriverIndex].dataSize = dataSize;
1191 handle->i2sQueue[queueDriverIndex].data = (uint8_t *)dataAddr;
1192 }
1193 }
1194
1195 /* Clear RX level interrupt flag */
1196 base->FIFOSTAT = I2S_FIFOSTAT_RXLVL(1U);
1197 }
1198 }
1199