1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016-2019 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_flexio_i2s.h"
10 
11 /* Component ID definition, used by tools. */
12 #ifndef FSL_COMPONENT_ID
13 #define FSL_COMPONENT_ID "platform.drivers.flexio_i2s"
14 #endif
15 
16 /*******************************************************************************
17  * Definitations
18  ******************************************************************************/
19 /*!@brief _sai_transfer_state*/
20 enum
21 {
22     kFLEXIO_I2S_Busy = 0x0U, /*!< FLEXIO_I2S is busy */
23     kFLEXIO_I2S_Idle,        /*!< Transfer is done. */
24 };
25 
26 /*******************************************************************************
27  * Prototypes
28  ******************************************************************************/
29 
30 /*!
31  * @brief Receive a piece of data in non-blocking way.
32  *
33  * @param base FLEXIO I2S base pointer
34  * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
35  * @param buffer Pointer to the data to be read.
36  * @param size Bytes to be read.
37  */
38 static void FLEXIO_I2S_ReadNonBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *rxData, size_t size);
39 
40 /*!
41  * @brief sends a piece of data in non-blocking way.
42  *
43  * @param base FLEXIO I2S base pointer
44  * @param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
45  * @param buffer Pointer to the data to be written.
46  * @param size Bytes to be written.
47  */
48 static void FLEXIO_I2S_WriteNonBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *txData, size_t size);
49 /*******************************************************************************
50  * Variables
51  ******************************************************************************/
52 
53 /*******************************************************************************
54  * Code
55  ******************************************************************************/
56 
FLEXIO_I2S_GetInstance(FLEXIO_I2S_Type * base)57 static uint32_t FLEXIO_I2S_GetInstance(FLEXIO_I2S_Type *base)
58 {
59     return FLEXIO_GetInstance(base->flexioBase);
60 }
61 
FLEXIO_I2S_WriteNonBlocking(FLEXIO_I2S_Type * base,uint8_t bitWidth,uint8_t * txData,size_t size)62 static void FLEXIO_I2S_WriteNonBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *txData, size_t size)
63 {
64     uint32_t i           = 0;
65     uint8_t j            = 0;
66     uint8_t bytesPerWord = bitWidth / 8U;
67     uint32_t data        = 0;
68     uint32_t temp        = 0;
69 
70     for (i = 0; i < size / bytesPerWord; i++)
71     {
72         for (j = 0; j < bytesPerWord; j++)
73         {
74             temp = (uint32_t)(*txData);
75             data |= (temp << (8U * j));
76             txData++;
77         }
78         base->flexioBase->SHIFTBUFBIS[base->txShifterIndex] = data << (32U - bitWidth);
79         data                                                = 0;
80     }
81 }
82 
FLEXIO_I2S_ReadNonBlocking(FLEXIO_I2S_Type * base,uint8_t bitWidth,uint8_t * rxData,size_t size)83 static void FLEXIO_I2S_ReadNonBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *rxData, size_t size)
84 {
85     uint32_t i           = 0;
86     uint8_t j            = 0;
87     uint8_t bytesPerWord = bitWidth / 8U;
88     uint32_t data        = 0;
89 
90     for (i = 0; i < size / bytesPerWord; i++)
91     {
92         data = (base->flexioBase->SHIFTBUFBIS[base->rxShifterIndex]);
93         for (j = 0; j < bytesPerWord; j++)
94         {
95             *rxData = (uint8_t)((data >> (8U * j)) & 0xFFU);
96             rxData++;
97         }
98     }
99 }
100 
101 /*!
102  * brief Initializes the FlexIO I2S.
103  *
104  * This API configures FlexIO pins and shifter to I2S and configures the FlexIO I2S with a configuration structure.
105  * The configuration structure can be filled by the user, or be set with default values by
106  * FLEXIO_I2S_GetDefaultConfig().
107  *
108  * note  This API should be called at the beginning of the application to use
109  * the FlexIO I2S driver. Otherwise, any access to the FlexIO I2S module can cause hard fault
110  * because the clock is not enabled.
111  *
112  * param base FlexIO I2S base pointer
113  * param config FlexIO I2S configure structure.
114  */
FLEXIO_I2S_Init(FLEXIO_I2S_Type * base,const flexio_i2s_config_t * config)115 void FLEXIO_I2S_Init(FLEXIO_I2S_Type *base, const flexio_i2s_config_t *config)
116 {
117     assert((base != NULL) && (config != NULL));
118 
119     flexio_shifter_config_t shifterConfig = {0};
120     flexio_timer_config_t timerConfig     = {0};
121 
122 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
123     /* Ungate flexio clock. */
124     CLOCK_EnableClock(s_flexioClocks[FLEXIO_I2S_GetInstance(base)]);
125 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
126 
127     /* reset Flexio */
128     FLEXIO_Reset(base->flexioBase);
129 
130     /* Set shifter for I2S Tx data */
131     shifterConfig.timerSelect   = base->bclkTimerIndex;
132     shifterConfig.pinSelect     = base->txPinIndex;
133     shifterConfig.timerPolarity = config->txTimerPolarity;
134     shifterConfig.pinConfig     = kFLEXIO_PinConfigOutput;
135     shifterConfig.pinPolarity   = config->txPinPolarity;
136     shifterConfig.shifterMode   = kFLEXIO_ShifterModeTransmit;
137     shifterConfig.inputSource   = kFLEXIO_ShifterInputFromPin;
138     shifterConfig.shifterStop   = kFLEXIO_ShifterStopBitDisable;
139     if (config->masterSlave == kFLEXIO_I2S_Master)
140     {
141         shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnShift;
142     }
143     else
144     {
145         shifterConfig.shifterStart = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
146     }
147 
148     FLEXIO_SetShifterConfig(base->flexioBase, base->txShifterIndex, &shifterConfig);
149 
150     /* Set shifter for I2S Rx Data */
151     shifterConfig.timerSelect   = base->bclkTimerIndex;
152     shifterConfig.pinSelect     = base->rxPinIndex;
153     shifterConfig.timerPolarity = config->rxTimerPolarity;
154     shifterConfig.pinConfig     = kFLEXIO_PinConfigOutputDisabled;
155     shifterConfig.pinPolarity   = config->rxPinPolarity;
156     shifterConfig.shifterMode   = kFLEXIO_ShifterModeReceive;
157     shifterConfig.inputSource   = kFLEXIO_ShifterInputFromPin;
158     shifterConfig.shifterStop   = kFLEXIO_ShifterStopBitDisable;
159     shifterConfig.shifterStart  = kFLEXIO_ShifterStartBitDisabledLoadDataOnEnable;
160 
161     FLEXIO_SetShifterConfig(base->flexioBase, base->rxShifterIndex, &shifterConfig);
162 
163     /* Set Timer to I2S frame sync */
164     if (config->masterSlave == kFLEXIO_I2S_Master)
165     {
166         timerConfig.triggerSelect   = FLEXIO_TIMER_TRIGGER_SEL_PININPUT(base->txPinIndex);
167         timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
168         timerConfig.triggerSource   = kFLEXIO_TimerTriggerSourceExternal;
169         timerConfig.pinConfig       = kFLEXIO_PinConfigOutput;
170         timerConfig.pinSelect       = base->fsPinIndex;
171         timerConfig.pinPolarity     = config->fsPinPolarity;
172         timerConfig.timerMode       = kFLEXIO_TimerModeSingle16Bit;
173         timerConfig.timerOutput     = kFLEXIO_TimerOutputOneNotAffectedByReset;
174         timerConfig.timerDecrement  = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
175         timerConfig.timerReset      = kFLEXIO_TimerResetNever;
176         timerConfig.timerDisable    = kFLEXIO_TimerDisableNever;
177         timerConfig.timerEnable     = kFLEXIO_TimerEnableOnPrevTimerEnable;
178         timerConfig.timerStart      = kFLEXIO_TimerStartBitDisabled;
179         timerConfig.timerStop       = kFLEXIO_TimerStopBitDisabled;
180     }
181     else
182     {
183         timerConfig.triggerSelect   = FLEXIO_TIMER_TRIGGER_SEL_PININPUT(base->bclkPinIndex);
184         timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
185         timerConfig.triggerSource   = kFLEXIO_TimerTriggerSourceInternal;
186         timerConfig.pinConfig       = kFLEXIO_PinConfigOutputDisabled;
187         timerConfig.pinSelect       = base->fsPinIndex;
188         timerConfig.pinPolarity     = config->fsPinPolarity;
189         timerConfig.timerMode       = kFLEXIO_TimerModeSingle16Bit;
190         timerConfig.timerOutput     = kFLEXIO_TimerOutputOneNotAffectedByReset;
191         timerConfig.timerDecrement  = kFLEXIO_TimerDecSrcOnTriggerInputShiftTriggerInput;
192         timerConfig.timerReset      = kFLEXIO_TimerResetNever;
193         timerConfig.timerDisable    = kFLEXIO_TimerDisableOnTimerCompare;
194         timerConfig.timerEnable     = kFLEXIO_TimerEnableOnPinRisingEdge;
195         timerConfig.timerStart      = kFLEXIO_TimerStartBitDisabled;
196         timerConfig.timerStop       = kFLEXIO_TimerStopBitDisabled;
197     }
198     FLEXIO_SetTimerConfig(base->flexioBase, base->fsTimerIndex, &timerConfig);
199 
200     /* Set Timer to I2S bit clock */
201     if (config->masterSlave == kFLEXIO_I2S_Master)
202     {
203         timerConfig.triggerSelect   = FLEXIO_TIMER_TRIGGER_SEL_SHIFTnSTAT(base->txShifterIndex);
204         timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveLow;
205         timerConfig.triggerSource   = kFLEXIO_TimerTriggerSourceInternal;
206         timerConfig.pinSelect       = base->bclkPinIndex;
207         timerConfig.pinConfig       = kFLEXIO_PinConfigOutput;
208         timerConfig.pinPolarity     = config->bclkPinPolarity;
209         timerConfig.timerMode       = kFLEXIO_TimerModeDual8BitBaudBit;
210         timerConfig.timerOutput     = kFLEXIO_TimerOutputOneNotAffectedByReset;
211         timerConfig.timerDecrement  = kFLEXIO_TimerDecSrcOnFlexIOClockShiftTimerOutput;
212         timerConfig.timerReset      = kFLEXIO_TimerResetNever;
213         timerConfig.timerDisable    = kFLEXIO_TimerDisableNever;
214         timerConfig.timerEnable     = kFLEXIO_TimerEnableOnTriggerHigh;
215         timerConfig.timerStart      = kFLEXIO_TimerStartBitEnabled;
216         timerConfig.timerStop       = kFLEXIO_TimerStopBitDisabled;
217     }
218     else
219     {
220         timerConfig.triggerSelect   = FLEXIO_TIMER_TRIGGER_SEL_TIMn(base->fsTimerIndex);
221         timerConfig.triggerPolarity = kFLEXIO_TimerTriggerPolarityActiveHigh;
222         timerConfig.triggerSource   = kFLEXIO_TimerTriggerSourceInternal;
223         timerConfig.pinSelect       = base->bclkPinIndex;
224         timerConfig.pinConfig       = kFLEXIO_PinConfigOutputDisabled;
225         timerConfig.pinPolarity     = config->bclkPinPolarity;
226         timerConfig.timerMode       = kFLEXIO_TimerModeSingle16Bit;
227         timerConfig.timerOutput     = kFLEXIO_TimerOutputOneNotAffectedByReset;
228         timerConfig.timerDecrement  = kFLEXIO_TimerDecSrcOnPinInputShiftPinInput;
229         timerConfig.timerReset      = kFLEXIO_TimerResetNever;
230         timerConfig.timerDisable    = kFLEXIO_TimerDisableOnTimerCompareTriggerLow;
231         timerConfig.timerEnable     = kFLEXIO_TimerEnableOnPinRisingEdgeTriggerHigh;
232         timerConfig.timerStart      = kFLEXIO_TimerStartBitDisabled;
233         timerConfig.timerStop       = kFLEXIO_TimerStopBitDisabled;
234     }
235     FLEXIO_SetTimerConfig(base->flexioBase, base->bclkTimerIndex, &timerConfig);
236 
237     /* If enable flexio I2S */
238     if (config->enableI2S)
239     {
240         base->flexioBase->CTRL |= FLEXIO_CTRL_FLEXEN_MASK;
241     }
242     else
243     {
244         base->flexioBase->CTRL &= ~FLEXIO_CTRL_FLEXEN_MASK;
245     }
246 }
247 
248 /*!
249  * brief  Sets the FlexIO I2S configuration structure to default values.
250  *
251  * The purpose of this API is to get the configuration structure initialized for use in FLEXIO_I2S_Init().
252  * Users may use the initialized structure unchanged in FLEXIO_I2S_Init() or modify
253  * some fields of the structure before calling FLEXIO_I2S_Init().
254  *
255  * param config pointer to master configuration structure
256  */
FLEXIO_I2S_GetDefaultConfig(flexio_i2s_config_t * config)257 void FLEXIO_I2S_GetDefaultConfig(flexio_i2s_config_t *config)
258 {
259     /* Initializes the configure structure to zero. */
260     (void)memset(config, 0, sizeof(*config));
261 
262     config->masterSlave     = kFLEXIO_I2S_Master;
263     config->enableI2S       = true;
264     config->txPinPolarity   = kFLEXIO_PinActiveHigh;
265     config->rxPinPolarity   = kFLEXIO_PinActiveHigh;
266     config->bclkPinPolarity = kFLEXIO_PinActiveHigh;
267     config->fsPinPolarity   = kFLEXIO_PinActiveLow;
268     config->txTimerPolarity = kFLEXIO_ShifterTimerPolarityOnPositive;
269     config->rxTimerPolarity = kFLEXIO_ShifterTimerPolarityOnNegitive;
270 }
271 
272 /*!
273  * brief De-initializes the FlexIO I2S.
274  *
275  * Calling this API resets the FlexIO I2S shifter and timer config. After calling this API,
276  * call the FLEXO_I2S_Init to use the FlexIO I2S module.
277  *
278  * param base FlexIO I2S base pointer
279  */
FLEXIO_I2S_Deinit(FLEXIO_I2S_Type * base)280 void FLEXIO_I2S_Deinit(FLEXIO_I2S_Type *base)
281 {
282     base->flexioBase->SHIFTCFG[base->txShifterIndex] = 0;
283     base->flexioBase->SHIFTCTL[base->txShifterIndex] = 0;
284     base->flexioBase->SHIFTCFG[base->rxShifterIndex] = 0;
285     base->flexioBase->SHIFTCTL[base->rxShifterIndex] = 0;
286     base->flexioBase->TIMCFG[base->fsTimerIndex]     = 0;
287     base->flexioBase->TIMCMP[base->fsTimerIndex]     = 0;
288     base->flexioBase->TIMCTL[base->fsTimerIndex]     = 0;
289     base->flexioBase->TIMCFG[base->bclkTimerIndex]   = 0;
290     base->flexioBase->TIMCMP[base->bclkTimerIndex]   = 0;
291     base->flexioBase->TIMCTL[base->bclkTimerIndex]   = 0;
292 }
293 
294 /*!
295  * brief Enables the FlexIO I2S interrupt.
296  *
297  * This function enables the FlexIO UART interrupt.
298  *
299  * param base Pointer to FLEXIO_I2S_Type structure
300  * param mask interrupt source
301  */
FLEXIO_I2S_EnableInterrupts(FLEXIO_I2S_Type * base,uint32_t mask)302 void FLEXIO_I2S_EnableInterrupts(FLEXIO_I2S_Type *base, uint32_t mask)
303 {
304     if ((mask & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyInterruptEnable) != 0UL)
305     {
306         FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->txShifterIndex);
307     }
308     if ((mask & (uint32_t)kFLEXIO_I2S_RxDataRegFullInterruptEnable) != 0UL)
309     {
310         FLEXIO_EnableShifterStatusInterrupts(base->flexioBase, 1UL << base->rxShifterIndex);
311     }
312 }
313 
314 /*!
315  * brief Gets the FlexIO I2S status flags.
316  *
317  * param base Pointer to FLEXIO_I2S_Type structure
318  * return Status flag, which are ORed by the enumerators in the _flexio_i2s_status_flags.
319  */
FLEXIO_I2S_GetStatusFlags(FLEXIO_I2S_Type * base)320 uint32_t FLEXIO_I2S_GetStatusFlags(FLEXIO_I2S_Type *base)
321 {
322     uint32_t status = 0;
323     status = ((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->txShifterIndex)) >> base->txShifterIndex);
324     status |=
325         (((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->rxShifterIndex)) >> (base->rxShifterIndex))
326          << 1U);
327     return status;
328 }
329 
330 /*!
331  * brief Disables the FlexIO I2S interrupt.
332  *
333  * This function enables the FlexIO UART interrupt.
334  *
335  * param base pointer to FLEXIO_I2S_Type structure
336  * param mask interrupt source
337  */
FLEXIO_I2S_DisableInterrupts(FLEXIO_I2S_Type * base,uint32_t mask)338 void FLEXIO_I2S_DisableInterrupts(FLEXIO_I2S_Type *base, uint32_t mask)
339 {
340     if ((mask & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyInterruptEnable) != 0UL)
341     {
342         FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->txShifterIndex);
343     }
344     if ((mask & (uint32_t)kFLEXIO_I2S_RxDataRegFullInterruptEnable) != 0UL)
345     {
346         FLEXIO_DisableShifterStatusInterrupts(base->flexioBase, 1UL << base->rxShifterIndex);
347     }
348 }
349 
350 /*!
351  * brief Configures the FlexIO I2S audio format in master mode.
352  *
353  * Audio format can be changed in run-time of FlexIO I2S. This function configures the sample rate and audio data
354  * format to be transferred.
355  *
356  * param base Pointer to FLEXIO_I2S_Type structure
357  * param format Pointer to FlexIO I2S audio data format structure.
358  * param srcClock_Hz I2S master clock source frequency in Hz.
359  */
FLEXIO_I2S_MasterSetFormat(FLEXIO_I2S_Type * base,flexio_i2s_format_t * format,uint32_t srcClock_Hz)360 void FLEXIO_I2S_MasterSetFormat(FLEXIO_I2S_Type *base, flexio_i2s_format_t *format, uint32_t srcClock_Hz)
361 {
362     uint32_t timDiv  = srcClock_Hz / (format->sampleRate_Hz * format->bitWidth * 2U);
363     uint32_t bclkDiv = 0;
364 
365     /* Shall keep bclk and fs div an integer */
366     if ((timDiv % 2UL) != 0UL)
367     {
368         timDiv += 1U;
369     }
370     /* Set Frame sync timer cmp */
371     base->flexioBase->TIMCMP[base->fsTimerIndex] = FLEXIO_TIMCMP_CMP(format->bitWidth * timDiv - 1U);
372 
373     /* Set bit clock timer cmp */
374     bclkDiv                                        = ((timDiv / 2U - 1U) | ((format->bitWidth * 2UL - 1UL) << 8U));
375     base->flexioBase->TIMCMP[base->bclkTimerIndex] = FLEXIO_TIMCMP_CMP(bclkDiv);
376 }
377 
378 /*!
379  * brief Configures the FlexIO I2S audio format in slave mode.
380  *
381  * Audio format can be changed in run-time of FlexIO I2S. This function configures the sample rate and audio data
382  * format to be transferred.
383  *
384  * param base Pointer to FLEXIO_I2S_Type structure
385  * param format Pointer to FlexIO I2S audio data format structure.
386  */
FLEXIO_I2S_SlaveSetFormat(FLEXIO_I2S_Type * base,flexio_i2s_format_t * format)387 void FLEXIO_I2S_SlaveSetFormat(FLEXIO_I2S_Type *base, flexio_i2s_format_t *format)
388 {
389     /* Set Frame sync timer cmp */
390     base->flexioBase->TIMCMP[base->fsTimerIndex] = FLEXIO_TIMCMP_CMP(format->bitWidth * 4UL - 3UL);
391 
392     /* Set bit clock timer cmp */
393     base->flexioBase->TIMCMP[base->bclkTimerIndex] = FLEXIO_TIMCMP_CMP(format->bitWidth * 2UL - 1UL);
394 }
395 
396 /*!
397  * brief Sends data using a blocking method.
398  *
399  * note This function blocks via polling until data is ready to be sent.
400  *
401  * param base FlexIO I2S base pointer.
402  * param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
403  * param txData Pointer to the data to be written.
404  * param size Bytes to be written.
405  * retval kStatus_Success Successfully write data.
406  * retval kStatus_FLEXIO_I2C_Timeout Timeout polling status flags.
407  */
FLEXIO_I2S_WriteBlocking(FLEXIO_I2S_Type * base,uint8_t bitWidth,uint8_t * txData,size_t size)408 status_t FLEXIO_I2S_WriteBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *txData, size_t size)
409 {
410     uint32_t i           = 0;
411     uint8_t bytesPerWord = bitWidth / 8U;
412 #if I2S_RETRY_TIMES
413     uint32_t waitTimes = I2S_RETRY_TIMES;
414 #endif
415 
416     for (i = 0; i < size / bytesPerWord; i++)
417     {
418         /* Wait until it can write data */
419 #if I2S_RETRY_TIMES
420         waitTimes = I2S_RETRY_TIMES;
421         while (((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) == 0UL) &&
422                (--waitTimes != 0U))
423         {
424         }
425         if (waitTimes == 0U)
426         {
427             return kStatus_FLEXIO_I2S_Timeout;
428         }
429 #else
430         while ((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) == 0UL)
431         {
432         }
433 #endif
434 
435         FLEXIO_I2S_WriteNonBlocking(base, bitWidth, txData, bytesPerWord);
436         txData = (uint8_t *)((uint32_t)txData + bytesPerWord);
437     }
438 
439     /* Wait until the last data is sent */
440 #if I2S_RETRY_TIMES
441     waitTimes = I2S_RETRY_TIMES;
442     while (((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) == 0UL) && (--waitTimes != 0U))
443     {
444     }
445     if (waitTimes == 0U)
446     {
447         return kStatus_FLEXIO_I2S_Timeout;
448     }
449 #else
450     while ((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) == 0UL)
451     {
452     }
453 #endif
454 
455     return kStatus_Success;
456 }
457 
458 /*!
459  * brief Receives a piece of data using a blocking method.
460  *
461  * note This function blocks via polling until data is ready to be sent.
462  *
463  * param base FlexIO I2S base pointer
464  * param bitWidth How many bits in a audio word, usually 8/16/24/32 bits.
465  * param rxData Pointer to the data to be read.
466  * param size Bytes to be read.
467  * retval kStatus_Success Successfully read data.
468  * retval kStatus_FLEXIO_I2C_Timeout Timeout polling status flags.
469  */
FLEXIO_I2S_ReadBlocking(FLEXIO_I2S_Type * base,uint8_t bitWidth,uint8_t * rxData,size_t size)470 status_t FLEXIO_I2S_ReadBlocking(FLEXIO_I2S_Type *base, uint8_t bitWidth, uint8_t *rxData, size_t size)
471 {
472     uint32_t i           = 0;
473     uint8_t bytesPerWord = bitWidth / 8U;
474 #if I2S_RETRY_TIMES
475     uint32_t waitTimes = I2S_RETRY_TIMES;
476 #endif
477 
478     for (i = 0; i < size / bytesPerWord; i++)
479     {
480         /* Wait until data is received */
481 #if I2S_RETRY_TIMES
482         waitTimes = I2S_RETRY_TIMES;
483         while ((!((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->rxShifterIndex)) != 0UL)) &&
484                (--waitTimes != 0U))
485         {
486         }
487         if (waitTimes == 0U)
488         {
489             return kStatus_FLEXIO_I2S_Timeout;
490         }
491 #else
492         while (!((FLEXIO_GetShifterStatusFlags(base->flexioBase) & (1UL << base->rxShifterIndex)) != 0UL))
493         {
494         }
495 #endif
496 
497         FLEXIO_I2S_ReadNonBlocking(base, bitWidth, rxData, bytesPerWord);
498         rxData = (uint8_t *)((uint32_t)rxData + bytesPerWord);
499     }
500     return kStatus_Success;
501 }
502 
503 /*!
504  * brief Initializes the FlexIO I2S handle.
505  *
506  * This function initializes the FlexIO I2S handle which can be used for other
507  * FlexIO I2S transactional APIs. Call this API once to get the
508  * initialized handle.
509  *
510  * param base Pointer to FLEXIO_I2S_Type structure
511  * param handle Pointer to flexio_i2s_handle_t structure to store the transfer state.
512  * param callback FlexIO I2S callback function, which is called while finished a block.
513  * param userData User parameter for the FlexIO I2S callback.
514  */
FLEXIO_I2S_TransferTxCreateHandle(FLEXIO_I2S_Type * base,flexio_i2s_handle_t * handle,flexio_i2s_callback_t callback,void * userData)515 void FLEXIO_I2S_TransferTxCreateHandle(FLEXIO_I2S_Type *base,
516                                        flexio_i2s_handle_t *handle,
517                                        flexio_i2s_callback_t callback,
518                                        void *userData)
519 {
520     assert(handle != NULL);
521 
522     IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
523 
524     /* Zero the handle. */
525     (void)memset(handle, 0, sizeof(*handle));
526 
527     /* Store callback and user data. */
528     handle->callback = callback;
529     handle->userData = userData;
530 
531     /* Save the context in global variables to support the double weak mechanism. */
532     (void)FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_I2S_TransferTxHandleIRQ);
533 
534     /* Set the TX/RX state. */
535     handle->state = (uint32_t)kFLEXIO_I2S_Idle;
536 
537     /* Enable interrupt in NVIC. */
538     (void)EnableIRQ(flexio_irqs[FLEXIO_I2S_GetInstance(base)]);
539 }
540 
541 /*!
542  * brief Initializes the FlexIO I2S receive handle.
543  *
544  * This function initializes the FlexIO I2S handle which can be used for other
545  * FlexIO I2S transactional APIs. Call this API once to get the
546  * initialized handle.
547  *
548  * param base Pointer to FLEXIO_I2S_Type structure.
549  * param handle Pointer to flexio_i2s_handle_t structure to store the transfer state.
550  * param callback FlexIO I2S callback function, which is called while finished a block.
551  * param userData User parameter for the FlexIO I2S callback.
552  */
FLEXIO_I2S_TransferRxCreateHandle(FLEXIO_I2S_Type * base,flexio_i2s_handle_t * handle,flexio_i2s_callback_t callback,void * userData)553 void FLEXIO_I2S_TransferRxCreateHandle(FLEXIO_I2S_Type *base,
554                                        flexio_i2s_handle_t *handle,
555                                        flexio_i2s_callback_t callback,
556                                        void *userData)
557 {
558     assert(handle != NULL);
559 
560     IRQn_Type flexio_irqs[] = FLEXIO_IRQS;
561 
562     /* Zero the handle. */
563     (void)memset(handle, 0, sizeof(*handle));
564 
565     /* Store callback and user data. */
566     handle->callback = callback;
567     handle->userData = userData;
568 
569     /* Save the context in global variables to support the double weak mechanism. */
570     (void)FLEXIO_RegisterHandleIRQ(base, handle, FLEXIO_I2S_TransferRxHandleIRQ);
571 
572     /* Set the TX/RX state. */
573     handle->state = (uint32_t)kFLEXIO_I2S_Idle;
574 
575     /* Enable interrupt in NVIC. */
576     (void)EnableIRQ(flexio_irqs[FLEXIO_I2S_GetInstance(base)]);
577 }
578 
579 /*!
580  * brief Configures the FlexIO I2S audio format.
581  *
582  * Audio format can be changed at run-time of FlexIO I2S. This function configures the sample rate and audio data
583  * format to be transferred.
584  *
585  * param base Pointer to FLEXIO_I2S_Type structure.
586  * param handle FlexIO I2S handle pointer.
587  * param format Pointer to audio data format structure.
588  * param srcClock_Hz FlexIO I2S bit clock source frequency in Hz. This parameter should be 0 while in slave mode.
589  */
FLEXIO_I2S_TransferSetFormat(FLEXIO_I2S_Type * base,flexio_i2s_handle_t * handle,flexio_i2s_format_t * format,uint32_t srcClock_Hz)590 void FLEXIO_I2S_TransferSetFormat(FLEXIO_I2S_Type *base,
591                                   flexio_i2s_handle_t *handle,
592                                   flexio_i2s_format_t *format,
593                                   uint32_t srcClock_Hz)
594 {
595     assert((handle != NULL) && (format != NULL));
596 
597     /* Set the bitWidth to handle */
598     handle->bitWidth = format->bitWidth;
599 
600     /* Set sample rate */
601     if (srcClock_Hz != 0UL)
602     {
603         /* It is master */
604         FLEXIO_I2S_MasterSetFormat(base, format, srcClock_Hz);
605     }
606     else
607     {
608         FLEXIO_I2S_SlaveSetFormat(base, format);
609     }
610 }
611 
612 /*!
613  * brief Performs an interrupt non-blocking send transfer on FlexIO I2S.
614  *
615  * note The API returns immediately after transfer initiates.
616  * Call FLEXIO_I2S_GetRemainingBytes to poll the transfer status and check whether
617  * the transfer is finished. If the return status is 0, the transfer is finished.
618  *
619  * param base Pointer to FLEXIO_I2S_Type structure.
620  * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
621  * param xfer Pointer to flexio_i2s_transfer_t structure
622  * retval kStatus_Success Successfully start the data transmission.
623  * retval kStatus_FLEXIO_I2S_TxBusy Previous transmission still not finished, data not all written to TX register yet.
624  * retval kStatus_InvalidArgument The input parameter is invalid.
625  */
FLEXIO_I2S_TransferSendNonBlocking(FLEXIO_I2S_Type * base,flexio_i2s_handle_t * handle,flexio_i2s_transfer_t * xfer)626 status_t FLEXIO_I2S_TransferSendNonBlocking(FLEXIO_I2S_Type *base,
627                                             flexio_i2s_handle_t *handle,
628                                             flexio_i2s_transfer_t *xfer)
629 {
630     assert(handle != NULL);
631 
632     /* Check if the queue is full */
633     if (handle->queue[handle->queueUser].data != NULL)
634     {
635         return kStatus_FLEXIO_I2S_QueueFull;
636     }
637     if ((xfer->dataSize == 0U) || (xfer->data == NULL))
638     {
639         return kStatus_InvalidArgument;
640     }
641 
642     /* Add into queue */
643     handle->queue[handle->queueUser].data     = xfer->data;
644     handle->queue[handle->queueUser].dataSize = xfer->dataSize;
645     handle->transferSize[handle->queueUser]   = xfer->dataSize;
646     handle->queueUser                         = (handle->queueUser + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
647 
648     /* Set the state to busy */
649     handle->state = (uint32_t)kFLEXIO_I2S_Busy;
650 
651     FLEXIO_I2S_EnableInterrupts(base, kFLEXIO_I2S_TxDataRegEmptyInterruptEnable);
652 
653     /* Enable Tx transfer */
654     FLEXIO_I2S_Enable(base, true);
655 
656     return kStatus_Success;
657 }
658 
659 /*!
660  * brief Performs an interrupt non-blocking receive transfer on FlexIO I2S.
661  *
662  * note The API returns immediately after transfer initiates.
663  * Call FLEXIO_I2S_GetRemainingBytes to poll the transfer status to check whether
664  * the transfer is finished. If the return status is 0, the transfer is finished.
665  *
666  * param base Pointer to FLEXIO_I2S_Type structure.
667  * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
668  * param xfer Pointer to flexio_i2s_transfer_t structure
669  * retval kStatus_Success Successfully start the data receive.
670  * retval kStatus_FLEXIO_I2S_RxBusy Previous receive still not finished.
671  * retval kStatus_InvalidArgument The input parameter is invalid.
672  */
FLEXIO_I2S_TransferReceiveNonBlocking(FLEXIO_I2S_Type * base,flexio_i2s_handle_t * handle,flexio_i2s_transfer_t * xfer)673 status_t FLEXIO_I2S_TransferReceiveNonBlocking(FLEXIO_I2S_Type *base,
674                                                flexio_i2s_handle_t *handle,
675                                                flexio_i2s_transfer_t *xfer)
676 {
677     assert(handle != NULL);
678 
679     /* Check if the queue is full */
680     if (handle->queue[handle->queueUser].data != NULL)
681     {
682         return kStatus_FLEXIO_I2S_QueueFull;
683     }
684 
685     if ((xfer->dataSize == 0U) || (xfer->data == NULL))
686     {
687         return kStatus_InvalidArgument;
688     }
689 
690     /* Add into queue */
691     handle->queue[handle->queueUser].data     = xfer->data;
692     handle->queue[handle->queueUser].dataSize = xfer->dataSize;
693     handle->transferSize[handle->queueUser]   = xfer->dataSize;
694     handle->queueUser                         = (handle->queueUser + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
695 
696     /* Set state to busy */
697     handle->state = (uint32_t)kFLEXIO_I2S_Busy;
698 
699     /* Enable interrupt */
700     FLEXIO_I2S_EnableInterrupts(base, kFLEXIO_I2S_RxDataRegFullInterruptEnable);
701 
702     /* Enable Rx transfer */
703     FLEXIO_I2S_Enable(base, true);
704 
705     return kStatus_Success;
706 }
707 
708 /*!
709  * brief Aborts the current send.
710  *
711  * note This API can be called at any time when interrupt non-blocking transfer initiates
712  * to abort the transfer in a early time.
713  *
714  * param base Pointer to FLEXIO_I2S_Type structure.
715  * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
716  */
FLEXIO_I2S_TransferAbortSend(FLEXIO_I2S_Type * base,flexio_i2s_handle_t * handle)717 void FLEXIO_I2S_TransferAbortSend(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle)
718 {
719     assert(handle != NULL);
720 
721     /* Stop Tx transfer and disable interrupt */
722     FLEXIO_I2S_DisableInterrupts(base, kFLEXIO_I2S_TxDataRegEmptyInterruptEnable);
723     handle->state = (uint32_t)kFLEXIO_I2S_Idle;
724 
725     /* Clear the queue */
726     (void)memset(handle->queue, 0, sizeof(flexio_i2s_transfer_t) * FLEXIO_I2S_XFER_QUEUE_SIZE);
727     handle->queueDriver = 0;
728     handle->queueUser   = 0;
729 }
730 
731 /*!
732  * brief Aborts the current receive.
733  *
734  * note This API can be called at any time when interrupt non-blocking transfer initiates
735  * to abort the transfer in a early time.
736  *
737  * param base Pointer to FLEXIO_I2S_Type structure.
738  * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
739  */
FLEXIO_I2S_TransferAbortReceive(FLEXIO_I2S_Type * base,flexio_i2s_handle_t * handle)740 void FLEXIO_I2S_TransferAbortReceive(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle)
741 {
742     assert(handle != NULL);
743 
744     /* Stop rx transfer and disable interrupt */
745     FLEXIO_I2S_DisableInterrupts(base, kFLEXIO_I2S_RxDataRegFullInterruptEnable);
746     handle->state = (uint32_t)kFLEXIO_I2S_Idle;
747 
748     /* Clear the queue */
749     (void)memset(handle->queue, 0, sizeof(flexio_i2s_transfer_t) * FLEXIO_I2S_XFER_QUEUE_SIZE);
750     handle->queueDriver = 0;
751     handle->queueUser   = 0;
752 }
753 
754 /*!
755  * brief Gets the remaining bytes to be sent.
756  *
757  * param base Pointer to FLEXIO_I2S_Type structure.
758  * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
759  * param count Bytes sent.
760  * retval kStatus_Success Succeed get the transfer count.
761  * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
762  */
FLEXIO_I2S_TransferGetSendCount(FLEXIO_I2S_Type * base,flexio_i2s_handle_t * handle,size_t * count)763 status_t FLEXIO_I2S_TransferGetSendCount(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle, size_t *count)
764 {
765     assert(handle != NULL);
766 
767     status_t status     = kStatus_Success;
768     uint8_t queueDriver = handle->queueDriver;
769 
770     if (handle->state != (uint32_t)kFLEXIO_I2S_Busy)
771     {
772         status = kStatus_NoTransferInProgress;
773     }
774     else
775     {
776         *count = (handle->transferSize[queueDriver] - handle->queue[queueDriver].dataSize);
777     }
778 
779     return status;
780 }
781 
782 /*!
783  * brief Gets the remaining bytes to be received.
784  *
785  * param base Pointer to FLEXIO_I2S_Type structure.
786  * param handle Pointer to flexio_i2s_handle_t structure which stores the transfer state
787  * return count Bytes received.
788  * retval kStatus_Success Succeed get the transfer count.
789  * retval kStatus_NoTransferInProgress There is not a non-blocking transaction currently in progress.
790  */
FLEXIO_I2S_TransferGetReceiveCount(FLEXIO_I2S_Type * base,flexio_i2s_handle_t * handle,size_t * count)791 status_t FLEXIO_I2S_TransferGetReceiveCount(FLEXIO_I2S_Type *base, flexio_i2s_handle_t *handle, size_t *count)
792 {
793     assert(handle != NULL);
794 
795     status_t status     = kStatus_Success;
796     uint8_t queueDriver = handle->queueDriver;
797 
798     if (handle->state != (uint32_t)kFLEXIO_I2S_Busy)
799     {
800         status = kStatus_NoTransferInProgress;
801     }
802     else
803     {
804         *count = (handle->transferSize[queueDriver] - handle->queue[queueDriver].dataSize);
805     }
806 
807     return status;
808 }
809 
810 /*!
811  * brief Tx interrupt handler.
812  *
813  * param i2sBase Pointer to FLEXIO_I2S_Type structure.
814  * param i2sHandle Pointer to flexio_i2s_handle_t structure
815  */
FLEXIO_I2S_TransferTxHandleIRQ(void * i2sBase,void * i2sHandle)816 void FLEXIO_I2S_TransferTxHandleIRQ(void *i2sBase, void *i2sHandle)
817 {
818     assert(i2sHandle != NULL);
819 
820     flexio_i2s_handle_t *handle = (flexio_i2s_handle_t *)i2sHandle;
821     FLEXIO_I2S_Type *base       = (FLEXIO_I2S_Type *)i2sBase;
822     uint8_t *buffer             = handle->queue[handle->queueDriver].data;
823     uint8_t dataSize            = handle->bitWidth / 8U;
824 
825     /* Handle error */
826     if ((FLEXIO_GetShifterErrorFlags(base->flexioBase) & (1UL << base->txShifterIndex)) != 0UL)
827     {
828         FLEXIO_ClearShifterErrorFlags(base->flexioBase, (1UL << base->txShifterIndex));
829     }
830     /* Handle transfer */
831     if (((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_TxDataRegEmptyFlag) != 0UL) &&
832         (handle->queue[handle->queueDriver].data != NULL))
833     {
834         FLEXIO_I2S_WriteNonBlocking(base, handle->bitWidth, buffer, dataSize);
835 
836         /* Update internal counter */
837         handle->queue[handle->queueDriver].dataSize -= dataSize;
838         handle->queue[handle->queueDriver].data =
839             (uint8_t *)((uint32_t)handle->queue[handle->queueDriver].data + dataSize);
840     }
841 
842     /* If finished a block, call the callback function */
843     if ((handle->queue[handle->queueDriver].dataSize == 0U) && (handle->queue[handle->queueDriver].data != NULL))
844     {
845         (void)memset(&handle->queue[handle->queueDriver], 0, sizeof(flexio_i2s_transfer_t));
846         handle->queueDriver = (handle->queueDriver + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
847         if (handle->callback != NULL)
848         {
849             (handle->callback)(base, handle, kStatus_Success, handle->userData);
850         }
851     }
852 
853     /* If all data finished, just stop the transfer */
854     if (handle->queue[handle->queueDriver].data == NULL)
855     {
856         FLEXIO_I2S_TransferAbortSend(base, handle);
857     }
858 }
859 
860 /*!
861  * brief Rx interrupt handler.
862  *
863  * param i2sBase Pointer to FLEXIO_I2S_Type structure.
864  * param i2sHandle Pointer to flexio_i2s_handle_t structure.
865  */
FLEXIO_I2S_TransferRxHandleIRQ(void * i2sBase,void * i2sHandle)866 void FLEXIO_I2S_TransferRxHandleIRQ(void *i2sBase, void *i2sHandle)
867 {
868     assert(i2sHandle != NULL);
869 
870     flexio_i2s_handle_t *handle = (flexio_i2s_handle_t *)i2sHandle;
871     FLEXIO_I2S_Type *base       = (FLEXIO_I2S_Type *)i2sBase;
872     uint8_t *buffer             = handle->queue[handle->queueDriver].data;
873     uint8_t dataSize            = handle->bitWidth / 8U;
874 
875     /* Handle transfer */
876     if (((FLEXIO_I2S_GetStatusFlags(base) & (uint32_t)kFLEXIO_I2S_RxDataRegFullFlag) != 0UL) &&
877         (handle->queue[handle->queueDriver].data != NULL))
878     {
879         FLEXIO_I2S_ReadNonBlocking(base, handle->bitWidth, buffer, dataSize);
880 
881         /* Update internal state */
882         handle->queue[handle->queueDriver].dataSize -= dataSize;
883         handle->queue[handle->queueDriver].data =
884             (uint8_t *)((uint32_t)handle->queue[handle->queueDriver].data + dataSize);
885     }
886 
887     /* If finished a block, call the callback function */
888     if ((handle->queue[handle->queueDriver].dataSize == 0U) && (handle->queue[handle->queueDriver].data != NULL))
889     {
890         (void)memset(&handle->queue[handle->queueDriver], 0, sizeof(flexio_i2s_transfer_t));
891         handle->queueDriver = (handle->queueDriver + 1U) % FLEXIO_I2S_XFER_QUEUE_SIZE;
892         if (handle->callback != NULL)
893         {
894             (handle->callback)(base, handle, kStatus_Success, handle->userData);
895         }
896     }
897 
898     /* If all data finished, just stop the transfer */
899     if (handle->queue[handle->queueDriver].data == NULL)
900     {
901         FLEXIO_I2S_TransferAbortReceive(base, handle);
902     }
903 }
904