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