1 /**
2 * @file i2s.c
3 * @brief Inter-Integrated Sound(I2S) driver implementation.
4 */
5
6 /******************************************************************************
7 *
8 * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
9 * Analog Devices, Inc.),
10 * Copyright (C) 2023-2024 Analog Devices, Inc.
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
26 #include <stddef.h>
27 #include <stdint.h>
28 #include "mxc_errors.h"
29 #include "mxc_device.h"
30 #include "mxc_assert.h"
31 #include "mxc_lock.h"
32 #include "mxc_sys.h"
33 #include "dma.h"
34 #include "i2s.h"
35 #include "i2s_reva.h"
36 #include "spimss.h"
37 #include "spimss_reva.h"
38
39 #define I2S_CHANNELS 2
40 #define I2S_WIDTH 16
41
42 static int tx_dma_channel = -1;
43 static int rx_dma_channel = -1;
44
MXC_I2S_RevA_Init(mxc_spimss_reva_regs_t * spimss,const mxc_i2s_config_t * config,void (* dma_ctz_cb)(int,int))45 int MXC_I2S_RevA_Init(mxc_spimss_reva_regs_t *spimss, const mxc_i2s_config_t *config,
46 void (*dma_ctz_cb)(int, int))
47 {
48 unsigned int baud;
49 uint16_t clkdiv;
50 uint8_t ctz_en;
51 int err;
52
53 mxc_dma_config_t dma_config;
54 mxc_dma_srcdst_t srcdst;
55
56 /* Setup SPI_MSS as master, mode 0, 16 bit transfers as I2S Requires */
57 spimss->ctrl = MXC_F_SPIMSS_REVA_CTRL_MMEN;
58 spimss->mode = MXC_S_SPIMSS_REVA_MODE_NUMBITS_BITS16 | MXC_F_SPIMSS_REVA_MODE_SS_IO;
59
60 spimss->dma = (1 << MXC_F_SPIMSS_DMA_TX_FIFO_LVL_POS) | /* TX DMA request FIFO level */
61 MXC_F_SPIMSS_DMA_TX_FIFO_CLR | /* Clear TX FIFO */
62 (1 << MXC_F_SPIMSS_DMA_RX_FIFO_LVL_POS) | /* RX DMA request FIFO level */
63 MXC_F_SPIMSS_DMA_RX_FIFO_CLR; /* Clear RX FIFO */
64
65 /* Setup I2S register from i2s_cfg_t */
66 spimss->i2s_ctrl = config->justify << MXC_F_SPIMSS_REVA_I2S_CTRL_I2S_LJ_POS |
67 config->audio_mode << MXC_F_SPIMSS_I2S_CTRL_I2S_MONO_POS;
68
69 /* Determine divisor for baud rate generator */
70 baud = config->sample_rate * I2S_CHANNELS * I2S_WIDTH;
71
72 if ((PeripheralClock / 4) < baud) {
73 return E_BAD_PARAM;
74 }
75
76 clkdiv = PeripheralClock / (2 * baud); // Peripheral clock in system_max*****.h
77
78 if (clkdiv < 2) {
79 return E_BAD_PARAM;
80 }
81
82 spimss->brg = clkdiv;
83
84 /* Prepare SPIMSS DMA register for DMA setup */
85 if (dma_ctz_cb == NULL) {
86 ctz_en = 0;
87 } else {
88 ctz_en = 1;
89 }
90
91 /* Initialize DMA */
92 if (config->audio_direction % 2) {
93 spimss->dma |= MXC_F_SPIMSS_REVA_DMA_TX_DMA_EN | MXC_F_SPIMSS_REVA_DMA_TX_FIFO_CLR;
94 if ((err = MXC_DMA_Init()) != E_NO_ERROR) {
95 if (err != E_BAD_STATE) {
96 return err;
97 }
98 }
99
100 if ((err = MXC_DMA_AcquireChannel()) < 0) {
101 return err;
102 }
103
104 tx_dma_channel = err;
105
106 dma_config.ch = tx_dma_channel;
107
108 dma_config.srcwd = MXC_DMA_WIDTH_WORD;
109 dma_config.dstwd = MXC_DMA_WIDTH_HALFWORD;
110 #if TARGET_NUM == 32650
111 dma_config.reqsel = MXC_DMA_REQUEST_SPIMSSTX;
112 #endif
113 #if TARGET_NUM == 32660
114 dma_config.reqsel = MXC_DMA_REQUEST_SPI1TX;
115 #endif
116
117 dma_config.srcinc_en = 1;
118 dma_config.dstinc_en = 0;
119
120 srcdst.ch = tx_dma_channel;
121 srcdst.source = config->src_addr;
122 srcdst.dest = NULL;
123 srcdst.len = config->length;
124
125 MXC_DMA_ConfigChannel(dma_config, srcdst);
126 MXC_DMA_SetChannelInterruptEn(tx_dma_channel, 0, 1);
127
128 MXC_DMA->ch[tx_dma_channel].cfg &= ~MXC_F_DMA_CFG_BRST;
129 MXC_DMA->ch[tx_dma_channel].cfg |= (3 << MXC_F_DMA_CFG_BRST_POS);
130
131 if (ctz_en) {
132 MXC_DMA_SetCallback(tx_dma_channel, dma_ctz_cb);
133 MXC_DMA_EnableInt(tx_dma_channel);
134 }
135 }
136 if (config->audio_direction / 2) {
137 spimss->dma |= MXC_F_SPIMSS_REVA_DMA_RX_DMA_EN | MXC_F_SPIMSS_REVA_DMA_RX_FIFO_CLR;
138 if ((err = MXC_DMA_Init()) != E_NO_ERROR) {
139 if (err != E_BAD_STATE) { //DMA already initialized
140 return err;
141 }
142 }
143
144 if ((err = MXC_DMA_AcquireChannel()) < 0) {
145 return err;
146 }
147
148 rx_dma_channel = err;
149
150 dma_config.ch = rx_dma_channel;
151
152 dma_config.srcwd = MXC_DMA_WIDTH_HALFWORD;
153 dma_config.dstwd = MXC_DMA_WIDTH_WORD;
154 #if TARGET_NUM == 32650
155 dma_config.reqsel = MXC_DMA_REQUEST_SPIMSSRX;
156 #endif
157 #if TARGET_NUM == 32660
158 dma_config.reqsel = MXC_DMA_REQUEST_SPI1RX;
159 #endif
160
161 dma_config.srcinc_en = 0;
162 dma_config.dstinc_en = 1;
163
164 srcdst.ch = rx_dma_channel;
165 srcdst.source = NULL;
166 srcdst.dest = config->dst_addr;
167 srcdst.len = config->length;
168
169 MXC_DMA_ConfigChannel(dma_config, srcdst);
170 MXC_DMA_SetChannelInterruptEn(rx_dma_channel, 0, 1);
171
172 MXC_DMA->ch[rx_dma_channel].cfg &= ~MXC_F_DMA_CFG_BRST;
173 MXC_DMA->ch[rx_dma_channel].cfg |= (3 << MXC_F_DMA_CFG_BRST_POS);
174
175 if (ctz_en) {
176 MXC_DMA_SetCallback(rx_dma_channel, dma_ctz_cb);
177 MXC_DMA_EnableInt(rx_dma_channel);
178 }
179 }
180
181 MXC_I2S_DMA_SetAddrCnt(config->src_addr, config->dst_addr, config->length);
182 if (config->dma_reload_en) {
183 MXC_I2S_DMA_SetReload(config->src_addr, config->dst_addr, config->length);
184 }
185
186 if (config->start_immediately) {
187 return MXC_I2S_Start();
188 }
189 return E_NO_ERROR;
190 }
191
MXC_I2S_RevA_Shutdown(mxc_spimss_reva_regs_t * spimss)192 int MXC_I2S_RevA_Shutdown(mxc_spimss_reva_regs_t *spimss)
193 {
194 int retTx = E_NO_ERROR;
195 int retRx = E_NO_ERROR;
196
197 spimss->ctrl = 0;
198 spimss->i2s_ctrl = 0;
199 spimss->brg = 0;
200 spimss->mode = 0;
201 spimss->dma = 0;
202
203 if (tx_dma_channel != -1) {
204 retTx = MXC_DMA_ReleaseChannel(tx_dma_channel);
205 }
206
207 if (rx_dma_channel != -1) {
208 retRx = MXC_DMA_ReleaseChannel(rx_dma_channel);
209 }
210
211 if (retTx != E_NO_ERROR) {
212 return retTx;
213 } else {
214 return retRx;
215 }
216 }
217
MXC_I2S_RevA_Mute(mxc_spimss_reva_regs_t * spimss)218 int MXC_I2S_RevA_Mute(mxc_spimss_reva_regs_t *spimss)
219 {
220 spimss->i2s_ctrl |= MXC_F_SPIMSS_REVA_I2S_CTRL_I2S_MUTE;
221 return E_NO_ERROR;
222 }
223
MXC_I2S_RevA_Unmute(mxc_spimss_reva_regs_t * spimss)224 int MXC_I2S_RevA_Unmute(mxc_spimss_reva_regs_t *spimss)
225 {
226 spimss->i2s_ctrl &= ~MXC_F_SPIMSS_REVA_I2S_CTRL_I2S_MUTE;
227 return E_NO_ERROR;
228 }
229
MXC_I2S_RevA_Pause(mxc_spimss_reva_regs_t * spimss)230 int MXC_I2S_RevA_Pause(mxc_spimss_reva_regs_t *spimss)
231 {
232 spimss->i2s_ctrl |= MXC_F_SPIMSS_REVA_I2S_CTRL_I2S_PAUSE;
233 return E_NO_ERROR;
234 }
235
MXC_I2S_RevA_Unpause(mxc_spimss_reva_regs_t * spimss)236 int MXC_I2S_RevA_Unpause(mxc_spimss_reva_regs_t *spimss)
237 {
238 spimss->i2s_ctrl &= ~MXC_F_SPIMSS_REVA_I2S_CTRL_I2S_PAUSE;
239 return E_NO_ERROR;
240 }
241
MXC_I2S_RevA_Stop(mxc_spimss_reva_regs_t * spimss)242 int MXC_I2S_RevA_Stop(mxc_spimss_reva_regs_t *spimss)
243 {
244 int retTx = E_NO_ERROR;
245 int retRx = E_NO_ERROR;
246
247 spimss->ctrl &= ~MXC_F_SPIMSS_REVA_CTRL_ENABLE;
248 spimss->i2s_ctrl &= ~MXC_F_SPIMSS_REVA_I2S_CTRL_I2S_EN;
249
250 if (tx_dma_channel != -1) {
251 retTx = MXC_DMA_Stop(tx_dma_channel);
252 }
253 if (rx_dma_channel != -1) {
254 retRx = MXC_DMA_Stop(rx_dma_channel);
255 }
256
257 if (retTx != E_NO_ERROR) {
258 return retTx;
259 } else {
260 return retRx;
261 }
262 }
263
MXC_I2S_RevA_Start(mxc_spimss_reva_regs_t * spimss)264 int MXC_I2S_RevA_Start(mxc_spimss_reva_regs_t *spimss)
265 {
266 int retTx = E_NO_ERROR;
267 int retRx = E_NO_ERROR;
268
269 spimss->ctrl |= MXC_F_SPIMSS_REVA_CTRL_ENABLE;
270 spimss->i2s_ctrl |= MXC_F_SPIMSS_REVA_I2S_CTRL_I2S_EN;
271
272 if (tx_dma_channel != -1) {
273 retTx = MXC_DMA_Start(tx_dma_channel);
274 }
275 if (rx_dma_channel != -1) {
276 retRx = MXC_DMA_Start(rx_dma_channel);
277 }
278
279 if (retTx != E_NO_ERROR) {
280 return retTx;
281 } else {
282 return retRx;
283 }
284 }
285
MXC_I2S_RevA_DMA_ClearFlags(void)286 int MXC_I2S_RevA_DMA_ClearFlags(void)
287 {
288 int retTx = E_NO_ERROR;
289 int retRx = E_NO_ERROR;
290
291 int flags;
292
293 if (tx_dma_channel != -1) {
294 flags = MXC_DMA_ChannelGetFlags(tx_dma_channel);
295 retTx = MXC_DMA_ChannelClearFlags(tx_dma_channel, flags);
296 }
297 if (rx_dma_channel != -1) {
298 flags = MXC_DMA_ChannelGetFlags(rx_dma_channel);
299 retRx = MXC_DMA_ChannelClearFlags(rx_dma_channel, flags);
300 }
301
302 if (retTx != E_NO_ERROR) {
303 return retTx;
304 } else {
305 return retRx;
306 }
307 }
308
MXC_I2S_RevA_DMA_SetAddrCnt(void * src_addr,void * dst_addr,unsigned int count)309 int MXC_I2S_RevA_DMA_SetAddrCnt(void *src_addr, void *dst_addr, unsigned int count)
310 {
311 int retTx = E_NO_ERROR;
312 int retRx = E_NO_ERROR;
313
314 mxc_dma_srcdst_t srcdst;
315
316 if (tx_dma_channel != -1) {
317 srcdst.ch = tx_dma_channel;
318 srcdst.source = src_addr;
319 srcdst.dest = dst_addr;
320 srcdst.len = count;
321 retTx = MXC_DMA_SetSrcDst(srcdst);
322 }
323 if (rx_dma_channel != -1) {
324 srcdst.ch = rx_dma_channel;
325 srcdst.source = src_addr;
326 srcdst.dest = dst_addr;
327 srcdst.len = count;
328 retRx = MXC_DMA_SetSrcDst(srcdst);
329 }
330
331 if (retTx != E_NO_ERROR) {
332 return retTx;
333 } else {
334 return retRx;
335 }
336 }
337
MXC_I2S_RevA_DMA_SetReload(void * src_addr,void * dst_addr,unsigned int count)338 int MXC_I2S_RevA_DMA_SetReload(void *src_addr, void *dst_addr, unsigned int count)
339 {
340 int retTx = E_NO_ERROR;
341 int retRx = E_NO_ERROR;
342
343 mxc_dma_srcdst_t srcdst;
344
345 if (tx_dma_channel != -1) {
346 srcdst.ch = tx_dma_channel;
347 srcdst.source = src_addr;
348 srcdst.dest = dst_addr;
349 srcdst.len = count;
350 retTx = MXC_DMA_SetSrcReload(srcdst);
351 }
352 if (rx_dma_channel != -1) {
353 srcdst.ch = rx_dma_channel;
354 srcdst.source = src_addr;
355 srcdst.dest = dst_addr;
356 srcdst.len = count;
357 retRx = MXC_DMA_SetSrcReload(srcdst);
358 }
359
360 if (retTx != E_NO_ERROR) {
361 return retTx;
362 } else {
363 return retRx;
364 }
365 }
366