1 /*
2  * Copyright (c) 2022-2023 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <rtthread.h>
9 #include <rtdevice.h>
10 
11 #define DBG_TAG              "i2s"
12 #define DBG_LVL              DBG_INFO
13 #include <rtdbg.h>
14 
15 #ifdef BSP_USING_I2S
16 #include "hpm_i2s_drv.h"
17 #include "board.h"
18 #ifdef HPMSOC_HAS_HPMSDK_DMAV2
19 #include "hpm_dmav2_drv.h"
20 #else
21 #include "hpm_dma_drv.h"
22 #endif
23 #include "hpm_dmamux_drv.h"
24 #include "hpm_l1c_drv.h"
25 #include "hpm_clock_drv.h"
26 #include "hpm_dma_mgr.h"
27 
28 #include "drv_i2s.h"
29 #include "drivers/dev_audio.h"
30 
31 static rt_ssize_t hpm_i2s_transmit(struct rt_audio_device* audio, const void* writeBuf, void* readBuf, rt_size_t size);
32 
33 /**
34  * I2S state
35  */
36 typedef enum {
37     hpm_i2s_state_stop,
38     hpm_i2s_state_read,
39     hpm_i2s_state_write,
40 } hpm_i2s_state_t;
41 
42 struct hpm_i2s
43 {
44     struct rt_audio_device audio;
45     struct rt_audio_configure audio_config;
46     dma_resource_t rx_dma_resource;
47     dma_resource_t tx_dma_resource;
48     char *dev_name;
49     I2S_Type *base;
50     clock_name_t clk_name;
51     i2s_transfer_config_t transfer;
52     uint8_t rx_dma_req;
53     uint8_t tx_dma_req;
54     rt_uint8_t* tx_buff;
55     rt_uint8_t* rx_buff;
56     hpm_i2s_state_t i2s_state;
57 };
58 
59 #if defined(BSP_USING_I2S0)
60 ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s0_tx_buff[I2S_FIFO_SIZE];
61 ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s0_rx_buff[I2S_FIFO_SIZE];
62 #endif
63 #if defined(BSP_USING_I2S1)
64 ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s1_tx_buff[I2S_FIFO_SIZE];
65 ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s1_rx_buff[I2S_FIFO_SIZE];
66 #endif
67 #if defined(BSP_USING_I2S2)
68 ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s2_tx_buff[I2S_FIFO_SIZE];
69 ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s2_rx_buff[I2S_FIFO_SIZE];
70 #endif
71 #if defined(BSP_USING_I2S3)
72 ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s3_tx_buff[I2S_FIFO_SIZE];
73 ATTR_ALIGN(HPM_L1C_CACHELINE_SIZE) uint8_t i2s3_rx_buff[I2S_FIFO_SIZE];
74 #endif
75 
76 static struct hpm_i2s hpm_i2s_set[] =
77 {
78 #if defined(BSP_USING_I2S0) && defined(HPM_I2S0)
79     {
80         .dev_name = "i2s0",
81         .base = HPM_I2S0,
82         .clk_name =  clock_i2s0,
83         .rx_dma_req = HPM_DMA_SRC_I2S0_RX,
84         .tx_dma_req = HPM_DMA_SRC_I2S0_TX,
85         .tx_buff = i2s0_tx_buff,
86         .rx_buff = i2s0_rx_buff,
87     },
88 #endif
89 #if defined(BSP_USING_I2S1) && defined(HPM_I2S1)
90     {
91         .dev_name = "i2s1",
92         .base = HPM_I2S1;
93         .clk_name =  clock_i2s1,
94         .rx_dma_req = HPM_DMA_SRC_I2S1_RX,
95         .tx_dma_req = HPM_DMA_SRC_I2S1_TX,
96         .tx_buff = i2s1_tx_buff,
97         .rx_buff = i2s1_rx_buff,
98     },
99 #endif
100 #if defined(BSP_USING_I2S2) && defined(HPM_I2S2)
101     {
102         .dev_name = "i2s2",
103         .base = HPM_I2S2,
104         .clk_name =  clock_i2s2,
105         .rx_dma_req = HPM_DMA_SRC_I2S2_RX,
106         .tx_dma_req = HPM_DMA_SRC_I2S2_TX,
107         .tx_buff = i2s2_tx_buff,
108         .rx_buff = i2s2_rx_buff,
109     },
110 #endif
111 #if defined(BSP_USING_I2S3) && defined(HPM_I2S3)
112     {
113         .dev_name = "i2s3",
114         .base = HPM_I2S3,
115         .clk_name =  clock_i2s3,
116         .rx_dma_req = HPM_DMA_SRC_I2S3_RX,
117         .tx_dma_req = HPM_DMA_SRC_I2S3_TX,
118         .tx_buff = i2s3_tx_buff,
119         .rx_buff = i2s3_rx_buff,
120     },
121 #endif
122 };
123 
124 /* I2S TX DMA callback function: trigger next transfer */
i2s_tx_dma_tc_callback(DMA_Type * ptr,uint32_t channel,void * user_data)125 void i2s_tx_dma_tc_callback(DMA_Type *ptr, uint32_t channel, void *user_data)
126 {
127     struct hpm_i2s* hpm_audio = (struct hpm_i2s*) user_data;
128     rt_audio_tx_complete(&hpm_audio->audio);
129 }
130 
131 /* I2S RX DMA callback function: write data into record->pipe and trigger next transfer */
i2s_rx_dma_tc_callback(DMA_Type * ptr,uint32_t channel,void * user_data)132 void i2s_rx_dma_tc_callback(DMA_Type *ptr, uint32_t channel, void *user_data)
133 {
134     struct hpm_i2s* hpm_audio = (struct hpm_i2s*) user_data;
135     rt_audio_rx_done(&hpm_audio->audio, hpm_audio->rx_buff, I2S_FIFO_SIZE);
136     hpm_i2s_transmit(&hpm_audio->audio, NULL, hpm_audio->rx_buff, I2S_FIFO_SIZE);
137 }
138 
139 
hpm_i2s_init(struct rt_audio_device * audio)140 static rt_err_t hpm_i2s_init(struct rt_audio_device* audio)
141 {
142     RT_ASSERT(audio != RT_NULL);
143     rt_uint32_t mclk_hz;
144     i2s_config_t i2s_config;
145     i2s_transfer_config_t transfer;
146 
147     struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
148 
149     init_i2s_pins(hpm_audio->base);
150     board_init_i2s_clock(hpm_audio->base);
151 
152     /* enable dma request */
153     i2s_enable_rx_dma_request(hpm_audio->base);
154     i2s_enable_tx_dma_request(hpm_audio->base);
155 
156     i2s_get_default_config(hpm_audio->base, &i2s_config);
157     i2s_config.enable_mclk_out = true;
158     i2s_init(hpm_audio->base, &i2s_config);
159 
160     mclk_hz = clock_get_frequency(hpm_audio->clk_name);
161     i2s_get_default_transfer_config(&transfer);
162     /* init I2S parameter */
163     transfer.sample_rate = 48000U;
164     transfer.protocol = I2S_PROTOCOL_LEFT_JUSTIFIED;
165     transfer.channel_slot_mask = I2S_CHANNEL_SLOT_MASK(0); /* one channel */
166     transfer.audio_depth = i2s_audio_depth_16_bits;
167     transfer.master_mode = true;
168     hpm_audio->transfer = transfer;
169     /* record i2s parameter to audio_config */
170     hpm_audio->audio_config.samplerate = 48000U;
171     hpm_audio->audio_config.samplebits = 16;
172     hpm_audio->audio_config.channels = 1;
173     if (status_success != i2s_config_transfer(hpm_audio->base, mclk_hz, &transfer))
174     {
175         LOG_E("dao_i2s configure transfer failed\n");
176         return -RT_ERROR;
177     }
178 
179     hpm_audio->i2s_state = hpm_i2s_state_stop;
180 
181     return RT_EOK;
182 }
183 
hpm_i2s_getcaps(struct rt_audio_device * audio,struct rt_audio_caps * caps)184 static rt_err_t hpm_i2s_getcaps(struct rt_audio_device* audio, struct rt_audio_caps* caps)
185 {
186     rt_err_t result = RT_EOK;
187 
188     RT_ASSERT(audio != RT_NULL);
189     struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
190 
191     switch(caps->main_type)
192     {
193         case AUDIO_TYPE_INPUT:
194         {
195             switch(caps->sub_type)
196             {
197                 case AUDIO_DSP_PARAM:
198                 {
199                     caps->udata.config.channels     = hpm_audio->audio_config.channels;
200                     caps->udata.config.samplebits   = hpm_audio->audio_config.samplebits;
201                     caps->udata.config.samplerate   = hpm_audio->audio_config.samplerate;
202                     break;
203                 }
204 
205                 case AUDIO_DSP_SAMPLERATE:
206                 {
207                     caps->udata.config.samplerate   = hpm_audio->audio_config.samplerate;
208                     break;
209                 }
210 
211                 case AUDIO_DSP_CHANNELS:
212                 {
213                     caps->udata.config.channels     = hpm_audio->audio_config.channels;
214                     break;
215                 }
216 
217                 case AUDIO_DSP_SAMPLEBITS:
218                 {
219                     caps->udata.config.samplebits   = hpm_audio->audio_config.samplebits;
220                     break;
221                 }
222 
223                 case AUDIO_PARM_I2S_DATA_LINE:
224                 {
225                     caps->udata.value               = hpm_audio->transfer.data_line;
226                     break;
227                 }
228 
229                 default:
230                 {
231                     result = -RT_ERROR;
232                     break;
233                 }
234             }
235             break;
236         }
237         case AUDIO_TYPE_OUTPUT:
238         {
239             switch(caps->sub_type)
240             {
241                 case AUDIO_DSP_PARAM:
242                 {
243                     caps->udata.config.samplerate   = hpm_audio->audio_config.samplerate;
244                     caps->udata.config.channels     = hpm_audio->audio_config.channels;
245                     caps->udata.config.samplebits   = hpm_audio->audio_config.samplebits;
246                     break;
247                 }
248 
249                 case AUDIO_DSP_SAMPLERATE:
250                 {
251                     caps->udata.config.samplerate   = hpm_audio->audio_config.samplerate;
252                     break;
253                 }
254 
255                 case AUDIO_DSP_CHANNELS:
256                 {
257                     caps->udata.config.channels     = hpm_audio->audio_config.channels;
258                     break;
259                 }
260 
261                 case AUDIO_DSP_SAMPLEBITS:
262                 {
263                     caps->udata.config.samplebits   = hpm_audio->audio_config.samplebits;
264                     break;
265                 }
266 
267                 case AUDIO_PARM_I2S_DATA_LINE:
268                 {
269                     caps->udata.value               = hpm_audio->transfer.data_line;
270                     break;
271                 }
272 
273                 default:
274                 {
275                     result = -RT_ERROR;
276                     break;
277                 }
278             }
279 
280             break;
281         }
282 
283         default:
284             result = -RT_ERROR;
285             break;
286     }
287 
288     return result;
289 }
290 
i2s_is_enabled(I2S_Type * ptr)291 static bool i2s_is_enabled(I2S_Type *ptr)
292 {
293     return ((ptr->CTRL & I2S_CTRL_I2S_EN_MASK) != 0);
294 }
295 
hpm_i2s_configure(struct rt_audio_device * audio,struct rt_audio_caps * caps)296 static rt_err_t hpm_i2s_configure(struct rt_audio_device* audio, struct rt_audio_caps* caps)
297 {
298     rt_err_t result = RT_EOK;
299     RT_ASSERT(audio != RT_NULL);
300     struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
301 
302     switch(caps->main_type)
303     {
304         case AUDIO_TYPE_OUTPUT:
305         {
306             switch(caps->sub_type)
307             {
308             case AUDIO_DSP_PARAM:
309             {
310                 hpm_audio->audio_config.samplerate = caps->udata.config.samplerate;
311                 hpm_audio->audio_config.samplebits = caps->udata.config.samplebits;
312                 hpm_audio->audio_config.channels = caps->udata.config.channels;
313                 break;
314             }
315 
316             case AUDIO_DSP_SAMPLERATE:
317             {
318                 hpm_audio->audio_config.samplerate = caps->udata.config.samplerate;
319                 break;
320             }
321 
322             case AUDIO_DSP_CHANNELS:
323             {
324                 hpm_audio->audio_config.channels = caps->udata.config.channels;
325                 break;
326             }
327 
328             case AUDIO_DSP_SAMPLEBITS:
329             {
330                 hpm_audio->audio_config.samplebits = caps->udata.config.samplebits;
331                 break;
332             }
333 
334             case AUDIO_PARM_I2S_DATA_LINE:
335             {
336                 hpm_audio->transfer.data_line      = caps->udata.value;
337                 break;
338             }
339 
340             default:
341                 result = -RT_ERROR;
342                 break;
343             }
344             break;
345         }
346         case AUDIO_TYPE_INPUT:
347         {
348             switch(caps->sub_type)
349             {
350 
351             case AUDIO_DSP_PARAM:
352             {
353                 hpm_audio->audio_config.samplerate = caps->udata.config.samplerate;
354                 hpm_audio->audio_config.channels   = caps->udata.config.channels;
355                 hpm_audio->audio_config.samplebits = caps->udata.config.samplebits;
356                 break;
357             }
358 
359             case AUDIO_DSP_SAMPLERATE:
360             {
361                 hpm_audio->audio_config.samplerate = caps->udata.config.samplerate;
362                 break;
363             }
364             case AUDIO_DSP_CHANNELS:
365             {
366                 hpm_audio->audio_config.channels = caps->udata.config.channels;
367                 break;
368             }
369 
370             case AUDIO_DSP_SAMPLEBITS:
371             {
372                 hpm_audio->audio_config.samplebits = caps->udata.config.samplebits;
373                 break;
374             }
375 
376             case AUDIO_PARM_I2S_DATA_LINE:
377             {
378                 hpm_audio->transfer.data_line      = caps->udata.value;
379                 break;
380             }
381 
382             default:
383                 result = -RT_ERROR;
384                 break;
385             }
386             break;
387         }
388 
389         default:
390             break;
391     }
392 
393     /* configure I2S transfer */
394     if (hpm_audio->audio_config.channels == i2s_mono_left) {
395         hpm_audio->transfer.channel_slot_mask = I2S_CHANNEL_SLOT_MASK(0);
396     } else if (hpm_audio->audio_config.channels == i2s_mono_right) {
397         hpm_audio->transfer.channel_slot_mask = I2S_CHANNEL_SLOT_MASK(1);
398     } else if(hpm_audio->audio_config.channels == 2) {
399         hpm_audio->transfer.channel_slot_mask = I2S_CHANNEL_SLOT_MASK(0) | I2S_CHANNEL_SLOT_MASK(1);
400     } else {
401         LOG_E("I2S not support channels number %d.\n", hpm_audio->audio_config.channels);
402         return -RT_ERROR;
403     }
404 
405     hpm_audio->transfer.sample_rate = hpm_audio->audio_config.samplerate;
406 
407     /* i2s dma only support sample bit: 16 and 32 bits */
408     assert(hpm_audio->audio_config.samplebits == 16 || hpm_audio->audio_config.samplebits == 32);
409     hpm_audio->transfer.audio_depth = hpm_audio->audio_config.samplebits;
410 
411     /* Stop I2S transfer if the I2S needs to be re-configured */
412     bool is_enabled = i2s_is_enabled(hpm_audio->base);
413     if (is_enabled)
414     {
415         if (hpm_audio->i2s_state == hpm_i2s_state_read)
416         {
417             dma_abort_channel(hpm_audio->rx_dma_resource.base, hpm_audio->rx_dma_resource.channel);
418         }
419         if (hpm_audio->i2s_state == hpm_i2s_state_write)
420         {
421             dma_abort_channel(hpm_audio->tx_dma_resource.base, hpm_audio->tx_dma_resource.channel);
422         }
423     }
424     if (status_success != i2s_config_transfer(hpm_audio->base, clock_get_frequency(hpm_audio->clk_name), &hpm_audio->transfer))
425     {
426         LOG_E("%s configure transfer failed.\n", hpm_audio->dev_name);
427         return -RT_ERROR;
428     }
429     /* Restore I2S to previous state */
430     if (is_enabled)
431     {
432         i2s_enable(hpm_audio->base);
433     }
434 
435     return result;
436 }
437 
hpm_i2s_start(struct rt_audio_device * audio,int stream)438 static rt_err_t hpm_i2s_start(struct rt_audio_device* audio, int stream)
439 {
440     RT_ASSERT(audio != RT_NULL);
441 
442     struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
443 
444     /*  request DMA resource for audio data transfer */
445     if (stream == AUDIO_STREAM_REPLAY) {
446         i2s_disable(hpm_audio->base);
447         i2s_disable_tx_dma_request(hpm_audio->base);
448         dma_resource_t *dma_resource = &hpm_audio->tx_dma_resource;
449         if (dma_mgr_request_resource(dma_resource) == status_success) {
450             uint8_t dmamux_ch;
451             dma_mgr_install_chn_tc_callback(dma_resource, i2s_tx_dma_tc_callback, hpm_audio);
452             dma_mgr_enable_dma_irq_with_priority(dma_resource, 1);
453             dmamux_ch = DMA_SOC_CHN_TO_DMAMUX_CHN(dma_resource->base, dma_resource->channel);
454             dmamux_config(HPM_DMAMUX, dmamux_ch, hpm_audio->tx_dma_req, true);
455         } else {
456             LOG_E("no dma resource available for I2S TX transfer.\n");
457             return -RT_ERROR;
458         }
459         i2s_reset_tx(hpm_audio->base); /* disable and reset tx */
460         /* fill 2 dummy data, it is suitable for 1/2 channel of audio */
461         if (i2s_fill_tx_dummy_data(hpm_audio->base, hpm_audio->transfer.data_line , 2) != status_success) {
462             return -RT_ERROR;
463         }
464         rt_audio_tx_complete(audio);
465         i2s_enable(hpm_audio->base);
466         i2s_enable_tx_dma_request(hpm_audio->base);
467     } else if (stream == AUDIO_STREAM_RECORD) {
468         i2s_disable(hpm_audio->base);
469         i2s_disable_rx_dma_request(hpm_audio->base);
470         dma_resource_t *dma_resource = &hpm_audio->rx_dma_resource;
471         if (dma_mgr_request_resource(dma_resource) == status_success) {
472             uint8_t dmamux_ch;
473             dma_mgr_install_chn_tc_callback(dma_resource, i2s_rx_dma_tc_callback, hpm_audio);
474             dma_mgr_enable_dma_irq_with_priority(dma_resource, 1);
475             dmamux_ch = DMA_SOC_CHN_TO_DMAMUX_CHN(dma_resource->base, dma_resource->channel);
476             dmamux_config(HPM_DMAMUX, dmamux_ch, hpm_audio->rx_dma_req, true);
477         } else {
478             LOG_E("no dma resource available for I2S RX transfer.\n");
479             return -RT_ERROR;
480         }
481         i2s_reset_rx(hpm_audio->base); /* disable and reset rx */
482         if (I2S_FIFO_SIZE != hpm_i2s_transmit(&hpm_audio->audio, NULL, hpm_audio->rx_buff, I2S_FIFO_SIZE)) {
483             return -RT_ERROR;
484         }
485         i2s_enable(hpm_audio->base);
486         i2s_enable_rx_dma_request(hpm_audio->base);
487     } else {
488         return -RT_ERROR;
489     }
490 
491     return RT_EOK;
492 }
493 
hpm_i2s_stop(struct rt_audio_device * audio,int stream)494 static rt_err_t hpm_i2s_stop(struct rt_audio_device* audio, int stream)
495 {
496     RT_ASSERT(audio != RT_NULL);
497     struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
498 
499     i2s_disable(hpm_audio->base);
500 
501     if (stream == AUDIO_STREAM_REPLAY) {
502         dma_resource_t *dma_resource = &hpm_audio->tx_dma_resource;
503         dma_abort_channel(dma_resource->base, dma_resource->channel);
504         dma_mgr_release_resource(dma_resource);
505     } else if (stream == AUDIO_STREAM_RECORD)
506     {
507         dma_resource_t *dma_resource = &hpm_audio->rx_dma_resource;
508         dma_abort_channel(dma_resource->base, dma_resource->channel);
509         dma_mgr_release_resource(dma_resource);
510     } else {
511         return -RT_ERROR;
512     }
513 
514     hpm_audio->i2s_state = hpm_i2s_state_stop;
515 
516     return RT_EOK;
517 }
518 
hpm_i2s_transmit(struct rt_audio_device * audio,const void * writeBuf,void * readBuf,rt_size_t size)519 static rt_ssize_t hpm_i2s_transmit(struct rt_audio_device* audio, const void* writeBuf, void* readBuf, rt_size_t size)
520 {
521     RT_ASSERT(audio != RT_NULL);
522     struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
523 
524     /* i2s dma only support sample bit: 16 and 32 bits */
525     uint8_t data_width;
526     uint8_t data_shift_byte;
527     if (hpm_audio->transfer.audio_depth == i2s_audio_depth_16_bits) {
528         data_width = DMA_TRANSFER_WIDTH_HALF_WORD;
529         data_shift_byte = 2U ; /* put 16bit data on high bit of register */
530     } else {
531         data_width = DMA_TRANSFER_WIDTH_WORD;
532         data_shift_byte = 0U;
533     }
534 
535     if(writeBuf != RT_NULL)
536     {
537         dma_resource_t *dma_resource = &hpm_audio->tx_dma_resource;
538         dma_channel_config_t ch_config = {0};
539         dma_default_channel_config(dma_resource->base, &ch_config);
540         ch_config.src_addr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)writeBuf);
541         ch_config.dst_addr = (uint32_t)&hpm_audio->base->TXD[hpm_audio->transfer.data_line] + data_shift_byte;
542         ch_config.src_width = data_width;
543         ch_config.dst_width = data_width;
544         ch_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;
545         ch_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
546         ch_config.size_in_byte = size;
547         ch_config.dst_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;
548         ch_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;
549 
550         if (l1c_dc_is_enabled()) {
551             /* cache writeback for sent buff */
552             l1c_dc_writeback((uint32_t)writeBuf, size);
553         }
554 
555         hpm_audio->i2s_state = hpm_i2s_state_write;
556         if (status_success != dma_setup_channel(dma_resource->base, dma_resource->channel, &ch_config, true)) {
557             LOG_E("dma setup channel failed\n");
558             return -RT_ERROR;
559         }
560     } else if (readBuf != RT_NULL){
561         dma_resource_t *dma_resource = &hpm_audio->rx_dma_resource;
562         dma_channel_config_t ch_config = {0};
563         dma_default_channel_config(dma_resource->base, &ch_config);
564         ch_config.src_addr = (uint32_t)&hpm_audio->base->RXD[hpm_audio->transfer.data_line] + data_shift_byte;
565         ch_config.dst_addr = core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)readBuf);
566         ch_config.src_width = data_width;
567         ch_config.dst_width = data_width;
568         ch_config.src_addr_ctrl = DMA_ADDRESS_CONTROL_FIXED;
569         ch_config.dst_addr_ctrl = DMA_ADDRESS_CONTROL_INCREMENT;
570         ch_config.size_in_byte = size;
571         ch_config.src_mode = DMA_HANDSHAKE_MODE_HANDSHAKE;
572         ch_config.src_burst_size = DMA_NUM_TRANSFER_PER_BURST_1T;
573 
574         hpm_audio->i2s_state = hpm_i2s_state_read;
575         if (status_success != dma_setup_channel(dma_resource->base, dma_resource->channel, &ch_config, true)) {
576             LOG_E("dma setup channel failed\n");
577             return -RT_ERROR;
578         }
579 
580         if (l1c_dc_is_enabled()) {
581             /* cache invalidate for receive buff */
582             l1c_dc_invalidate((uint32_t)readBuf, size);
583         }
584     }
585 
586     return size;
587 }
588 
hpm_i2s_buffer_info(struct rt_audio_device * audio,struct rt_audio_buf_info * info)589 static void hpm_i2s_buffer_info(struct rt_audio_device* audio, struct rt_audio_buf_info* info)
590 {
591     RT_ASSERT(audio != RT_NULL);
592     struct hpm_i2s* hpm_audio = (struct hpm_i2s*)audio->parent.user_data;
593     /**
594      *               AUD_FIFO
595      * +----------------+----------------+
596      * |     block1     |     block2     |
597      * +----------------+----------------+
598      *  \  block_size  /
599      */
600     info->buffer      = hpm_audio->tx_buff;
601     info->total_size  = I2S_FIFO_SIZE;
602     info->block_size  = I2S_FIFO_SIZE / 2;
603     info->block_count = 2;
604 }
605 
606 
607 static struct rt_audio_ops hpm_i2s_ops =
608 {
609     .getcaps     = hpm_i2s_getcaps,
610     .configure   = hpm_i2s_configure,
611     .init        = hpm_i2s_init,
612     .start       = hpm_i2s_start,
613     .stop        = hpm_i2s_stop,
614     .transmit    = hpm_i2s_transmit,
615     .buffer_info = hpm_i2s_buffer_info,
616 };
617 
rt_hw_i2s_init(void)618 int rt_hw_i2s_init(void)
619 {
620     rt_err_t ret = RT_EOK;
621 
622     for (uint32_t i = 0; i < sizeof(hpm_i2s_set) / sizeof(hpm_i2s_set[0]); i++) {
623         hpm_i2s_set[i].audio.ops = &hpm_i2s_ops;
624 
625         ret = rt_audio_register(&hpm_i2s_set[i].audio, hpm_i2s_set[i].dev_name, RT_DEVICE_FLAG_RDWR, &hpm_i2s_set[i]);
626 
627         if (ret != RT_EOK)
628         {
629             LOG_E("rt audio %s register failed, status=%d\n", hpm_i2s_set[i].dev_name, ret);
630         }
631 
632     }
633 
634     return RT_EOK;
635 }
636 INIT_DEVICE_EXPORT(rt_hw_i2s_init);
637 
638 
639 #endif /* BSP_USING_I2S */
640