• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  *
15  * Description: Provides i2s driver source \n
16  *
17  * History: \n
18  * 2022-09-16, Create file. \n
19  */
20 #include "common_def.h"
21 #include "errcode.h"
22 #include "soc_osal.h"
23 #include "hal_sio.h"
24 #include "i2s.h"
25 #if defined(CONFIG_I2S_SUPPORT_DMA)
26 #include "dma.h"
27 #include "dma_porting.h"
28 #include "sio_porting.h"
29 
30 #define I2S_DMA_TRANS_MEMORY_TO_PERIPHERAL_DMA      1
31 #define I2S_DMA_TRANS_PERIPHERAL_TO_MEMORY_DMA      2
32 #define I2S_DMA_TRANSFER_DIR_MEM_TO_PERIPHERAL      0
33 #define I2S_DMA_TRANSFER_DIR_PERIPHERAL_TO_MEM      1
34 #define I2S_DMA_ADDRESS_INC_INCREMENT               0
35 #define I2S_DMA_ADDRESS_INC_NO_CHANGE               2
36 #define I2S_DMA_PROTECTION_CONTROL_BUFFERABLE       1
37 
38 typedef struct i2s_dma_trans_inf {
39     bool trans_succ;
40     uint8_t channel;
41     osal_semaphore dma_sem;
42 } i2s_dma_trans_inf_t;
43 
44 static i2s_dma_trans_inf_t g_tx_dma_trans[I2S_MAX_NUMBER] = { 0 };
45 static i2s_dma_trans_inf_t g_rx_dma_trans[I2S_MAX_NUMBER] = { 0 };
46 #endif
47 
48 static hal_sio_funcs_t *g_hal_funcs = NULL;
49 static bool g_i2s_inited = false;
50 
51 static hal_sio_config_t g_hal_config = {
52     .drive_mode= (hal_sio_driver_mode_t)0,
53     .transfer_mode = (hal_sio_transfer_mode_t)0,
54     .data_width = (hal_sio_data_width_t)0,
55     .channels_num = (hal_sio_channel_number_t)0,
56     .timing = (hal_sio_timing_mode_t)0,
57     .clk_edge = (hal_sio_clk_edge_t)0,
58     .div_number = 0,
59     .number_of_channels = 0,
60 };
61 
uapi_i2s_init(sio_bus_t bus,i2s_callback_t callback)62 errcode_t uapi_i2s_init(sio_bus_t bus, i2s_callback_t callback)
63 {
64     if (unlikely(g_i2s_inited)) {
65         return ERRCODE_SUCC;
66     }
67     if (unlikely(bus >= CONFIG_I2S_BUS_MAX_NUM)) {
68         return ERRCODE_INVALID_PARAM;
69     }
70 
71     sio_porting_register_hal_funcs(bus);
72     g_hal_funcs = hal_sio_get_funcs(bus);
73 
74     g_hal_funcs->init(bus);
75     g_hal_funcs->registerfunc(bus, (i2s_callback_t)callback);
76 
77     sio_porting_clock_enable(true);
78 #if defined(CONFIG_I2S_SUPPORT_DMA)
79     osal_sem_init(&(g_tx_dma_trans[bus].dma_sem), 0);
80     osal_sem_init(&(g_rx_dma_trans[bus].dma_sem), 0);
81 #endif
82     g_i2s_inited = true;
83     return ERRCODE_SUCC;
84 }
85 
uapi_i2s_deinit(sio_bus_t bus)86 errcode_t uapi_i2s_deinit(sio_bus_t bus)
87 {
88     if (unlikely(!g_i2s_inited)) {
89         return ERRCODE_SUCC;
90     }
91 
92     if (unlikely(bus >= CONFIG_I2S_BUS_MAX_NUM)) {
93         return ERRCODE_INVALID_PARAM;
94     }
95 
96     g_hal_funcs->rx_enable(bus, false);
97     g_hal_funcs->unregisterfunc(bus);
98     g_hal_funcs->deinit(bus);
99 
100     sio_porting_unregister_hal_funcs(bus);
101     sio_porting_unregister_irq(bus);
102 
103     sio_porting_clock_enable(false);
104     g_i2s_inited = false;
105     return ERRCODE_SUCC;
106 }
107 
uapi_i2s_set_config(sio_bus_t bus,const i2s_config_t * config)108 errcode_t uapi_i2s_set_config(sio_bus_t bus, const i2s_config_t *config)
109 {
110     if (unlikely(!g_i2s_inited)) {
111         return ERRCODE_I2S_NOT_INIT;
112     }
113     if (unlikely(bus >= CONFIG_I2S_BUS_MAX_NUM || config == NULL)) {
114         return ERRCODE_INVALID_PARAM;
115     }
116 
117     hal_sio_config_t hal_config = {
118         .drive_mode= (hal_sio_driver_mode_t)config->drive_mode,
119         .transfer_mode = (hal_sio_transfer_mode_t)config->transfer_mode,
120         .data_width = (hal_sio_data_width_t)config->data_width,
121         .channels_num = (hal_sio_channel_number_t)config->channels_num,
122         .timing = (hal_sio_timing_mode_t)config->timing,
123         .clk_edge = (hal_sio_clk_edge_t)config->clk_edge,
124         .div_number = config->div_number,
125         .number_of_channels = config->number_of_channels,
126     };
127     g_hal_funcs->set_config(bus, &hal_config);
128     return ERRCODE_SUCC;
129 }
130 
uapi_i2s_get_config(sio_bus_t bus,i2s_config_t * config)131 errcode_t uapi_i2s_get_config(sio_bus_t bus, i2s_config_t *config)
132 {
133     if (unlikely(!g_i2s_inited)) {
134         return ERRCODE_I2S_NOT_INIT;
135     }
136     if (unlikely(bus >= CONFIG_I2S_BUS_MAX_NUM || config == NULL)) {
137         return ERRCODE_INVALID_PARAM;
138     }
139 
140     errcode_t ret = g_hal_funcs->get_config(bus, &g_hal_config);
141 
142     config->drive_mode = g_hal_config.drive_mode;
143     config->transfer_mode = g_hal_config.transfer_mode;
144     config->data_width = g_hal_config.data_width;
145     config->channels_num = g_hal_config.channels_num;
146     config->timing = g_hal_config.timing;
147     config->clk_edge = g_hal_config.clk_edge;
148     config->div_number = g_hal_config.div_number;
149     config->number_of_channels = g_hal_config.number_of_channels;
150 
151     return ret;
152 }
153 
uapi_i2s_get_data(sio_bus_t bus,i2s_rx_data_t * data)154 errcode_t uapi_i2s_get_data(sio_bus_t bus, i2s_rx_data_t *data)
155 {
156     if (unlikely(!g_i2s_inited)) {
157         return ERRCODE_I2S_NOT_INIT;
158     }
159     if (unlikely(bus >= CONFIG_I2S_BUS_MAX_NUM)) {
160         return ERRCODE_INVALID_PARAM;
161     }
162 
163     if (data == NULL) {
164         return ERRCODE_INVALID_PARAM;
165     }
166 
167     i2s_rx_data_t *temp_data = data;
168 
169     g_hal_funcs->get_data(bus, (hal_sio_rx_data_t *)(uintptr_t)temp_data);
170 
171     return ERRCODE_SUCC;
172 }
173 
uapi_i2s_write_data(sio_bus_t bus,i2s_tx_data_t * data)174 errcode_t uapi_i2s_write_data(sio_bus_t bus, i2s_tx_data_t *data)
175 {
176     if (unlikely(!g_i2s_inited)) {
177         return ERRCODE_I2S_NOT_INIT;
178     }
179     if (unlikely(bus >= CONFIG_I2S_BUS_MAX_NUM)) {
180         return ERRCODE_INVALID_PARAM;
181     }
182 
183     if (data == NULL || data->left_buff == NULL || data->right_buff == NULL) {
184         return ERRCODE_INVALID_PARAM;
185     }
186 
187     g_hal_funcs->write(bus, (hal_sio_tx_data_t *)(uintptr_t)data, I2S_MODE);
188 
189     return ERRCODE_SUCC;
190 }
191 
uapi_i2s_read_start(sio_bus_t bus)192 errcode_t uapi_i2s_read_start(sio_bus_t bus)
193 {
194     if (unlikely(!g_i2s_inited)) {
195         return ERRCODE_I2S_NOT_INIT;
196     }
197     if (unlikely(bus >= CONFIG_I2S_BUS_MAX_NUM)) {
198         return ERRCODE_INVALID_PARAM;
199     }
200 
201     g_hal_funcs->rx_enable(bus, true);
202 
203     return ERRCODE_SUCC;
204 }
205 
uapi_i2s_loop_trans(sio_bus_t bus,i2s_tx_data_t * data)206 errcode_t uapi_i2s_loop_trans(sio_bus_t bus, i2s_tx_data_t *data)
207 {
208     if (unlikely(!g_i2s_inited)) {
209         return ERRCODE_I2S_NOT_INIT;
210     }
211     if (unlikely(bus >= CONFIG_I2S_BUS_MAX_NUM)) {
212         return ERRCODE_INVALID_PARAM;
213     }
214 
215     if (data == NULL || data->left_buff == NULL || data->right_buff == NULL) {
216         return ERRCODE_INVALID_PARAM;
217     }
218 
219     g_hal_funcs->loop_trans(bus, (hal_sio_tx_data_t *)(uintptr_t)data, I2S_MODE);
220 
221     return ERRCODE_SUCC;
222 }
223 
224 #if defined(CONFIG_I2S_SUPPORT_LOOPBACK) && (CONFIG_I2S_SUPPORT_LOOPBACK == 1)
uapi_i2s_loopback(sio_bus_t bus,bool en)225 errcode_t uapi_i2s_loopback(sio_bus_t bus, bool en)
226 {
227     if (unlikely(!g_i2s_inited)) {
228         return ERRCODE_I2S_NOT_INIT;
229     }
230     if (unlikely(bus >= CONFIG_I2S_BUS_MAX_NUM)) {
231         return ERRCODE_INVALID_PARAM;
232     }
233 
234     g_hal_funcs->loop(bus, en);
235 
236     return ERRCODE_SUCC;
237 }
238 #endif /* CONFIG_I2S_SUPPORT_LOOPBACK */
239 #if defined(CONFIG_I2S_SUPPORT_DMA)
uapi_i2s_dma_config(sio_bus_t bus,i2s_dma_attr_t * i2s_dma_cfg)240 int32_t uapi_i2s_dma_config(sio_bus_t bus, i2s_dma_attr_t *i2s_dma_cfg)
241 {
242     if (unlikely(!g_i2s_inited)) {
243         return ERRCODE_I2S_NOT_INIT;
244     }
245     if (unlikely(bus >= CONFIG_I2S_BUS_MAX_NUM)) {
246         return ERRCODE_INVALID_PARAM;
247     }
248     g_hal_funcs->dma_cfg(bus, (uintptr_t)i2s_dma_cfg);
249     return ERRCODE_SUCC;
250 }
251 
i2s_dma_rx_isr(uint8_t int_type,uint8_t ch,uintptr_t arg)252 static void i2s_dma_rx_isr(uint8_t int_type, uint8_t ch, uintptr_t arg)
253 {
254     unused(arg);
255     uint8_t bus = I2S_MAX_NUMBER;
256     for (uint8_t i = SIO_BUS_0; i < I2S_MAX_NUMBER; i++) {
257         if (g_rx_dma_trans[i].channel == ch) {
258             bus = i;
259             break;
260         }
261     }
262 
263     if (bus != I2S_MAX_NUMBER) {
264         if (int_type == 0) {
265             g_rx_dma_trans[bus].trans_succ = true;
266         }
267         osal_sem_up(&(g_rx_dma_trans[bus].dma_sem));
268     }
269 }
270 
i2s_dma_tx_isr(uint8_t int_type,uint8_t ch,uintptr_t arg)271 static void i2s_dma_tx_isr(uint8_t int_type, uint8_t ch, uintptr_t arg)
272 {
273     unused(arg);
274     uint8_t bus = I2S_MAX_NUMBER;
275     for (uint8_t i = SIO_BUS_0; i < I2S_MAX_NUMBER; i++) {
276         if (g_tx_dma_trans[i].channel == ch) {
277             bus = i;
278             break;
279         }
280     }
281 
282     if (bus != I2S_MAX_NUMBER) {
283         if (int_type == 0) {
284             g_tx_dma_trans[bus].trans_succ = true;
285         }
286         osal_sem_up(&(g_tx_dma_trans[bus].dma_sem));
287     }
288 }
289 
i2s_dma_peripheral_tx_config(dma_ch_user_peripheral_config_t * user_cfg,i2s_dma_config_t * dma_cfg,uint32_t length)290 static void i2s_dma_peripheral_tx_config(dma_ch_user_peripheral_config_t *user_cfg,
291     i2s_dma_config_t *dma_cfg, uint32_t length)
292 {
293     user_cfg->transfer_num = length;
294     user_cfg->src_handshaking = 0;
295     user_cfg->trans_type = I2S_DMA_TRANS_MEMORY_TO_PERIPHERAL_DMA;
296     user_cfg->trans_dir = I2S_DMA_TRANSFER_DIR_MEM_TO_PERIPHERAL;
297     user_cfg->priority = dma_cfg->priority;
298     user_cfg->src_width = dma_cfg->src_width;
299     user_cfg->dest_width = dma_cfg->dest_width;
300     user_cfg->burst_length = dma_cfg->burst_length;
301     user_cfg->src_increment = I2S_DMA_ADDRESS_INC_INCREMENT;
302     user_cfg->dest_increment = I2S_DMA_ADDRESS_INC_NO_CHANGE;
303     user_cfg->protection = I2S_DMA_PROTECTION_CONTROL_BUFFERABLE;
304     user_cfg->dest_handshaking = i2s_port_get_dma_trans_dest_handshaking(0);
305 }
306 
uapi_i2s_merge_write_by_dma(sio_bus_t bus,const void * buffer,uint32_t length,i2s_dma_config_t * dma_cfg,uintptr_t arg,bool block)307 int32_t uapi_i2s_merge_write_by_dma(sio_bus_t bus, const void *buffer, uint32_t length,
308     i2s_dma_config_t *dma_cfg, uintptr_t arg, bool block)
309 {
310     if (unlikely(!g_i2s_inited)) {
311         return ERRCODE_I2S_NOT_INIT;
312     }
313     if ((bus >= I2S_MAX_NUMBER) || (dma_cfg == NULL)) {
314         return ERRCODE_INVALID_PARAM;
315     }
316     if ((buffer == NULL) || (length == 0)) {
317         return ERRCODE_INVALID_PARAM;
318     }
319     dma_ch_user_peripheral_config_t user_cfg;
320     uint8_t dma_ch;
321     user_cfg.src = (uint32_t)(uintptr_t)buffer;
322     user_cfg.dest = (uint32_t)i2s_porting_tx_merge_data_addr_get(bus);
323     i2s_dma_peripheral_tx_config(&user_cfg, dma_cfg, length);
324     if (user_cfg.dest_handshaking == HAL_DMA_HANDSHAKING_MAX_NUM) {
325         return ERRCODE_NOT_SUPPORT;
326     }
327     if (uapi_dma_configure_peripheral_transfer_single(&user_cfg, &dma_ch, i2s_dma_tx_isr, arg) != ERRCODE_SUCC) {
328         return ERRCODE_FAIL;
329     }
330 
331     g_tx_dma_trans[bus].channel = dma_ch;
332     g_tx_dma_trans[bus].trans_succ = false;
333 
334     if (uapi_dma_start_transfer(dma_ch) != ERRCODE_SUCC) {
335         return ERRCODE_FAIL;
336     }
337     hal_sio_set_crg_clock_enable(bus, true);
338     hal_sio_set_tx_enable(bus, 1);
339     if (!block) {
340         return ERRCODE_SUCC;
341     }
342 
343     if (osal_sem_down(&(g_tx_dma_trans[bus].dma_sem)) != OSAL_SUCCESS) {
344         return ERRCODE_FAIL;
345     }
346 
347     if (!g_tx_dma_trans[bus].trans_succ) {
348         return ERRCODE_FAIL;
349     }
350     return (int32_t)uapi_dma_get_block_ts(dma_ch);
351 }
352 
i2s_dma_peripheral_rx_config(dma_ch_user_peripheral_config_t * user_cfg,i2s_dma_config_t * dma_cfg,uint32_t length)353 static void i2s_dma_peripheral_rx_config(dma_ch_user_peripheral_config_t *user_cfg,
354     i2s_dma_config_t *dma_cfg, uint32_t length)
355 {
356     user_cfg->transfer_num = length;
357     user_cfg->dest_handshaking = 0;
358     user_cfg->trans_type = I2S_DMA_TRANS_PERIPHERAL_TO_MEMORY_DMA;
359     user_cfg->trans_dir = I2S_DMA_TRANSFER_DIR_PERIPHERAL_TO_MEM;
360     user_cfg->priority = dma_cfg->priority;
361     user_cfg->src_width = dma_cfg->src_width;
362     user_cfg->dest_width = dma_cfg->dest_width;
363     user_cfg->burst_length = dma_cfg->burst_length;
364     user_cfg->src_increment = I2S_DMA_ADDRESS_INC_NO_CHANGE;
365     user_cfg->dest_increment = I2S_DMA_ADDRESS_INC_INCREMENT;
366     user_cfg->protection = I2S_DMA_PROTECTION_CONTROL_BUFFERABLE;
367     user_cfg->src_handshaking = i2s_port_get_dma_trans_src_handshaking(0);
368 }
369 
uapi_i2s_merge_read_by_dma(sio_bus_t bus,const void * buffer,uint32_t length,i2s_dma_config_t * dma_cfg,uintptr_t arg,bool block)370 int32_t uapi_i2s_merge_read_by_dma(sio_bus_t bus, const void *buffer, uint32_t length,
371     i2s_dma_config_t *dma_cfg, uintptr_t arg, bool block)
372 {
373     if (unlikely(!g_i2s_inited)) {
374         return ERRCODE_I2S_NOT_INIT;
375     }
376     if ((bus >= I2S_MAX_NUMBER) || (dma_cfg == NULL)) {
377         return ERRCODE_INVALID_PARAM;
378     }
379     if ((buffer == NULL) || (length == 0)) {
380         return ERRCODE_INVALID_PARAM;
381     }
382     dma_ch_user_peripheral_config_t user_cfg;
383     uint8_t dma_ch;
384     user_cfg.src = (uint32_t)i2s_porting_rx_merge_data_addr_get(bus);
385     user_cfg.dest = (uint32_t)(uintptr_t)buffer;
386     i2s_dma_peripheral_rx_config(&user_cfg, dma_cfg, length);
387     if (user_cfg.src_handshaking == HAL_DMA_HANDSHAKING_MAX_NUM) {
388         return ERRCODE_NOT_SUPPORT;
389     }
390     if (uapi_dma_configure_peripheral_transfer_single(&user_cfg, &dma_ch, i2s_dma_rx_isr, arg) != ERRCODE_SUCC) {
391         return ERRCODE_FAIL;
392     }
393 
394     g_rx_dma_trans[bus].channel = dma_ch;
395     g_rx_dma_trans[bus].trans_succ = false;
396     if (uapi_dma_start_transfer(dma_ch) != ERRCODE_SUCC) {
397         return ERRCODE_FAIL;
398     }
399     hal_sio_set_rx_enable(bus, 1);
400     if (!block) {
401         return ERRCODE_SUCC;
402     }
403 
404     if (osal_sem_down(&(g_rx_dma_trans[bus].dma_sem)) != OSAL_SUCCESS) {
405         return ERRCODE_FAIL;
406     }
407     if (!g_rx_dma_trans[bus].trans_succ) {
408         return ERRCODE_FAIL;
409     }
410     return (int32_t)uapi_dma_get_block_ts(dma_ch);
411 }
412 #endif