1 /***************************************************************************//**
2 * \file cy_i2s.c
3 * \version 2.30
4 *
5 * The source code file for the I2S driver.
6 *
7 ********************************************************************************
8 * \copyright
9 * Copyright 2016-2020 Cypress Semiconductor Corporation
10 * SPDX-License-Identifier: Apache-2.0
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 *     http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *******************************************************************************/
24 
25 #include "cy_device.h"
26 
27 #if (defined (AUDIOSS_I2S_PRESENT) || defined(CY_DOXYGEN))
28 
29 #include "cy_i2s.h"
30 
31 
32 /*******************************************************************************
33 * Function Name: Cy_I2S_Init
34 ****************************************************************************//**
35 *
36 * Initializes the I2S module in accordance with a configuration structure.
37 *
38 * \pre If the I2S module is initialized previously, the \ref Cy_I2S_DeInit()
39 * must be called before calling this function.
40 *
41 * \param base      The pointer to the I2S instance address.
42 *
43 * \param config    The pointer to a configuration structure.
44 *
45 * \return error / status code. See \ref cy_en_i2s_status_t.
46 *
47 * \funcusage
48 * \snippet i2s/snippet/main.c snippet_Cy_I2S_Init
49 *
50 *******************************************************************************/
Cy_I2S_Init(I2S_Type * base,cy_stc_i2s_config_t const * config)51 cy_en_i2s_status_t Cy_I2S_Init(I2S_Type * base, cy_stc_i2s_config_t const * config)
52 {
53     cy_en_i2s_status_t ret = CY_I2S_BAD_PARAM;
54 
55     if((NULL != base) && (NULL != config))
56     {
57         cy_en_i2s_ws_pw_t wsPulseWidth;
58         cy_en_i2s_len_t channelLength;
59         uint32_t channels;
60         uint32_t clockDiv = (uint32_t)config->clkDiv - 1U;
61 
62         CY_ASSERT_L2(CY_I2S_IS_CLK_DIV_VALID(clockDiv));
63 
64         REG_I2S_INTR_MASK(base) = 0UL; /* Disable interrupts prior to stopping the operation */
65         REG_I2S_CMD(base) = 0UL; /* Stop any communication */
66         REG_I2S_TR_CTL(base) = 0UL; /* Disable any DMA triggers */
67         REG_I2S_CTL(base) = 0UL; /* Disable TX/RX sub-blocks before clock changing */
68 
69         /* The clock setting */
70 
71 #if (CY_IP_MXAUDIOSS_VERSION>=2)
72         REG_I2S_CLOCK_CTL(base) = _VAL2FLD(I2S_CLOCK_CTL_CLOCK_DIV, clockDiv) |
73                                   _BOOL2FLD(I2S_CLOCK_CTL_CLOCK_SEL, config->extClk) |
74                                   _VAL2FLD(I2S_CLOCK_CTL_CLOCK_DIV, config->mclkDiv) |
75                                   _BOOL2FLD(I2S_CLOCK_CTL_CLOCK_SEL, config->mclkEn);
76 #else
77         REG_I2S_CLOCK_CTL(base) = _VAL2FLD(I2S_CLOCK_CTL_CLOCK_DIV, clockDiv) |
78                                   _BOOL2FLD(I2S_CLOCK_CTL_CLOCK_SEL, config->extClk);
79 #endif
80         /* The Tx setting */
81         if (config->txEnabled)
82         {
83             CY_ASSERT_L3(CY_I2S_IS_ALIGNMENT_VALID(config->txAlignment));
84             CY_ASSERT_L3(CY_I2S_IS_OVHDATA_VALID(config->txOverheadValue));
85 
86             if ((CY_I2S_TDM_MODE_A == config->txAlignment) || (CY_I2S_TDM_MODE_B == config->txAlignment))
87             {
88                 channels = (uint32_t)config->txChannels - 1UL;
89                 wsPulseWidth = config->txWsPulseWidth;
90                 channelLength = CY_I2S_LEN32;
91 
92                 CY_ASSERT_L2(CY_I2S_IS_CHANNELS_VALID(channels));
93                 CY_ASSERT_L3(CY_I2S_IS_WSPULSE_VALID(wsPulseWidth));
94                 CY_ASSERT_L3(CY_I2S_IS_LEN_VALID(config->txWordLength));
95             }
96             else
97             {
98                 channels = 1UL;
99                 wsPulseWidth = CY_I2S_WS_ONE_CHANNEL_LENGTH;
100                 channelLength = config->txChannelLength;
101 
102                 CY_ASSERT_L3(CY_I2S_IS_CHAN_WORD_VALID(channelLength, config->txWordLength));
103             }
104 
105             CY_ASSERT_L2(CY_I2S_IS_TRIG_LEVEL_VALID(config->txFifoTriggerLevel, channels));
106 
107             REG_I2S_TX_WATCHDOG(base) = config->txWatchdogValue;
108 
109             REG_I2S_TX_CTL(base) = _VAL2FLD(I2S_TX_CTL_I2S_MODE, config->txAlignment) |
110                                   _BOOL2FLD(I2S_TX_CTL_B_CLOCK_INV, config->txSdoLatchingTime) |
111                                    _VAL2FLD(I2S_TX_CTL_CH_NR, channels) |
112                                   _BOOL2FLD(I2S_TX_CTL_MS, config->txMasterMode) |
113                                    _VAL2FLD(I2S_TX_CTL_WS_PULSE, wsPulseWidth) |
114                                   _BOOL2FLD(I2S_TX_CTL_WD_EN, config->txWatchdogEnable) |
115                                   _BOOL2FLD(I2S_TX_CTL_SCKO_POL, config->txSckoInversion) |
116                                   _BOOL2FLD(I2S_TX_CTL_SCKI_POL, config->txSckiInversion) |
117                                    _VAL2FLD(I2S_TX_CTL_CH_LEN, channelLength) |
118                                    _VAL2FLD(I2S_TX_CTL_WORD_LEN, config->txWordLength) |
119                                    _VAL2FLD(I2S_TX_CTL_OVHDATA, config->txOverheadValue);
120         }
121 
122         /* The Rx setting */
123         if (config->rxEnabled)
124         {
125             CY_ASSERT_L3(CY_I2S_IS_ALIGNMENT_VALID(config->rxAlignment));
126 
127             if ((CY_I2S_TDM_MODE_A == config->rxAlignment) || (CY_I2S_TDM_MODE_B == config->rxAlignment))
128             {
129                 channels = (uint32_t)config->rxChannels - 1UL;
130                 wsPulseWidth = config->rxWsPulseWidth;
131                 channelLength = CY_I2S_LEN32;
132 
133                 CY_ASSERT_L2(CY_I2S_IS_CHANNELS_VALID(channels));
134                 CY_ASSERT_L3(CY_I2S_IS_WSPULSE_VALID(wsPulseWidth));
135                 CY_ASSERT_L3(CY_I2S_IS_LEN_VALID(config->rxWordLength));
136             }
137             else
138             {
139                 channels = 1UL;
140                 wsPulseWidth = CY_I2S_WS_ONE_CHANNEL_LENGTH;
141                 channelLength = config->rxChannelLength;
142 
143                 CY_ASSERT_L3(CY_I2S_IS_CHAN_WORD_VALID(channelLength, config->rxWordLength));
144             }
145 
146             CY_ASSERT_L2(CY_I2S_IS_TRIG_LEVEL_VALID(config->rxFifoTriggerLevel, channels));
147 
148             REG_I2S_RX_WATCHDOG(base) = config->rxWatchdogValue;
149 
150             REG_I2S_RX_CTL(base) = _VAL2FLD(I2S_RX_CTL_I2S_MODE, config->rxAlignment) |
151                                   _BOOL2FLD(I2S_RX_CTL_B_CLOCK_INV, config->rxSdiLatchingTime) |
152                                    _VAL2FLD(I2S_RX_CTL_CH_NR, channels) |
153                                   _BOOL2FLD(I2S_RX_CTL_MS, config->rxMasterMode) |
154                                    _VAL2FLD(I2S_RX_CTL_WS_PULSE, wsPulseWidth) |
155                                   _BOOL2FLD(I2S_RX_CTL_WD_EN, config->rxWatchdogEnable) |
156                                   _BOOL2FLD(I2S_RX_CTL_SCKO_POL, config->rxSckoInversion) |
157                                   _BOOL2FLD(I2S_RX_CTL_SCKI_POL, config->rxSckiInversion) |
158                                    _VAL2FLD(I2S_RX_CTL_CH_LEN, channelLength) |
159                                    _VAL2FLD(I2S_RX_CTL_WORD_LEN, config->rxWordLength) |
160                                   _BOOL2FLD(I2S_RX_CTL_BIT_EXTENSION, config->rxSignExtension);
161         }
162 
163         /* The I2S enable setting */
164         if (config->txEnabled)
165         {
166             REG_I2S_CTL(base) |= I2S_CTL_TX_ENABLED_Msk;
167         }
168 
169         if (config->rxEnabled)
170         {
171             REG_I2S_CTL(base) |= I2S_CTL_RX_ENABLED_Msk;
172         }
173 
174         /* The FIFO setting */
175         if (config->txEnabled)
176         {
177             REG_I2S_TX_FIFO_CTL(base) = _VAL2FLD(I2S_TX_FIFO_CTL_TRIGGER_LEVEL, config->txFifoTriggerLevel);
178 
179             REG_I2S_TR_CTL(base) |= _BOOL2FLD(I2S_TR_CTL_TX_REQ_EN, config->txDmaTrigger);
180         }
181 
182         if (config->rxEnabled)
183         {
184             REG_I2S_RX_FIFO_CTL(base) = _VAL2FLD(I2S_RX_FIFO_CTL_TRIGGER_LEVEL, config->rxFifoTriggerLevel);
185 
186             REG_I2S_TR_CTL(base) |= _BOOL2FLD(I2S_TR_CTL_RX_REQ_EN, config->rxDmaTrigger);
187         }
188 
189         ret = CY_I2S_SUCCESS;
190     }
191 
192     return (ret);
193 }
194 
195 
196 /*******************************************************************************
197 * Function Name: Cy_I2S_DeInit
198 ****************************************************************************//**
199 *
200 * Uninitializes the I2S module (reverts default register values).
201 *
202 * \param base The pointer to the I2S instance address.
203 *
204 * \funcusage
205 * \snippet i2s/snippet/main.c snippet_Cy_I2S_DeInit
206 *
207 *******************************************************************************/
Cy_I2S_DeInit(I2S_Type * base)208 void Cy_I2S_DeInit(I2S_Type * base)
209 {
210     REG_I2S_INTR_MASK(base) = 0UL; /* Disable interrupts prior to stopping the operation */
211     REG_I2S_CMD(base) = 0UL;
212     REG_I2S_TR_CTL(base) = 0UL;
213     REG_I2S_TX_FIFO_CTL(base) = 0UL;
214     REG_I2S_RX_FIFO_CTL(base) = 0UL;
215     REG_I2S_CTL(base) = 0UL;
216     REG_I2S_TX_CTL(base) = CY_I2S_TX_CTL_DEFAULT;
217     REG_I2S_RX_CTL(base) = CY_I2S_RX_CTL_DEFAULT;
218     REG_I2S_TX_WATCHDOG(base) = 0UL;
219     REG_I2S_RX_WATCHDOG(base) = 0UL;
220     REG_I2S_CLOCK_CTL(base) = 0UL;
221 }
222 
223 
224 /*******************************************************************************
225 * Function Name: Cy_I2S_DeepSleepCallback
226 ****************************************************************************//**
227 *
228 * This is a callback function to be used at the application layer to
229 * manage an I2S operation during the Deep Sleep cycle. It stores the I2S state
230 * (Tx/Rx enabled/disabled/paused) into the context structure and stops the
231 * communication before entering into Deep Sleep power mode and restores the I2S
232 * state after waking up.
233 *
234 * \param
235 * callbackParams - The pointer to the callback parameters structure,
236 * see \ref cy_stc_syspm_callback_params_t.
237 *
238 * \param mode
239 * Callback mode, see \ref cy_en_syspm_callback_mode_t
240 *
241 * \return the SysPm callback status \ref cy_en_syspm_status_t.
242 *
243 * \note Use the \ref cy_stc_i2s_context_t data type for definition of the
244 * *context element of the \ref cy_stc_syspm_callback_params_t structure.
245 *
246 * \funcusage
247 * \snippet i2s/snippet/main.c snippet_Cy_I2S_DeepSleepCallback
248 *
249 *******************************************************************************/
Cy_I2S_DeepSleepCallback(cy_stc_syspm_callback_params_t const * callbackParams,cy_en_syspm_callback_mode_t mode)250 cy_en_syspm_status_t Cy_I2S_DeepSleepCallback (cy_stc_syspm_callback_params_t const *callbackParams, cy_en_syspm_callback_mode_t mode)
251 {
252     cy_en_syspm_status_t ret = CY_SYSPM_SUCCESS;
253     CY_ASSERT_L1(NULL != callbackParams->context);
254     I2S_Type * locBase = (I2S_Type*) callbackParams->base;
255     uint32_t * locInterruptMask = (uint32_t*) &(((cy_stc_i2s_context_t*)(callbackParams->context))->interruptMask);
256     uint32_t * locState = (uint32_t*) &(((cy_stc_i2s_context_t*)(callbackParams->context))->enableState);
257 
258     switch(mode)
259     {
260         case CY_SYSPM_CHECK_READY:
261         case CY_SYSPM_CHECK_FAIL:
262             break;
263 
264         case CY_SYSPM_BEFORE_TRANSITION:
265             *locInterruptMask = Cy_I2S_GetInterruptMask(locBase); /* Store I2S interrupts */
266             *locState = Cy_I2S_GetCurrentState(locBase); /* Store I2S state */
267             if (0UL != (*locState & I2S_CMD_TX_START_Msk))
268             {
269                 Cy_I2S_DisableTx(locBase); /* Stop TX operation */
270             }
271             if (0UL != (*locState & I2S_CMD_RX_START_Msk))
272             {
273                 Cy_I2S_DisableRx(locBase); /* Stop RX operation */
274             }
275             Cy_I2S_SetInterruptMask(locBase, 0UL); /* Disable I2S interrupts */
276             /* Unload FIFOs to not lose data (if needed) */
277             break;
278 
279         case CY_SYSPM_AFTER_TRANSITION:
280             if (0UL != (*locState & I2S_CMD_RX_START_Msk))
281             {
282                 Cy_I2S_ClearRxFifo(locBase); /* Clear the RX FIFO */
283                 Cy_I2S_EnableRx(locBase); /* Start RX operation */
284             }
285             if (0UL != (*locState & I2S_CMD_TX_START_Msk))
286             {
287                 Cy_I2S_ClearTxFifo(locBase); /* Clear the TX FIFO */
288                 Cy_I2S_WriteTxData(locBase, 0UL); /* Fill at least one TX frame */
289                 Cy_I2S_WriteTxData(locBase, 0UL);
290                 if (0UL != (*locState & I2S_CMD_TX_PAUSE_Msk))
291                 {
292                     Cy_I2S_PauseTx(locBase); /* Restore the TX paused state */
293                 }
294                 Cy_I2S_EnableTx(locBase); /* Start TX operation */
295             }
296             Cy_I2S_ClearInterrupt(locBase, *locInterruptMask); /* Clear possible pending I2S interrupts */
297             Cy_I2S_SetInterruptMask(locBase, *locInterruptMask); /* Restore I2S interrupts */
298             break;
299 
300         default:
301             ret = CY_SYSPM_FAIL;
302             break;
303     }
304 
305     return(ret);
306 }
307 
308 
309 #endif /* CY_IP_MXAUDIOSS */
310 
311 /* [] END OF FILE */
312