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