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